Reputation: 320
I want to update the student state correctly, a student is an object that contains user, city and grades objects. I can do it in the updateStudent function, but the parameter data is not strict and has a type any.
I want to restrict the parameter data to IUser | ICity | IGrade, what would be the best procedure for this case?
interface IUser {
name?: string;
id?: number;
}
interface ICity {
city?: string;
zip?: number;
}
interface IGrade {
math?: string;
biology?: string;
}
interface IStudent {
user: IUser;
city: ICity;
grades: IGrade;
}
const [student, setStudent] = useState<IStudent>({
user: {},
city: {},
grade: {},
});
const updateStudent = (data: any, key: string) => {
setStudent({ ...student, [key]: data });
};
Upvotes: 0
Views: 155
Reputation: 20142
const updateStudent = <S extends IStudent, K extends keyof S>(data: S[K], key: K) => {
setStudent({ ...student, [key]: data });
};
Solution is to use two generic types: S
and K
. data
argument is defined as type of value for key K
, and key
represents K
. TypeScript is able to inference both types without any type annotation during calling the function.
Two generic types are crucial, as this is the way how to inform that we have relation between two arguments.data: S[K], key: K
, data
will represented as type of value picked by key
.
One thing to add, because the key defines the data, and not the other way around, better would be to have first argument as key and second as data.
Upvotes: 2