Dość ciekawy przypadek, niby prosty, ale często TS w takich właśnie „niby prostych” przypadkach potrafi przyprawić o niezły mętlik w głowie. Zaczynajmy!
Ok, mamy taki interfejsik, bardzo prosty:
interface SimpleInter {
a: number;
b: number;
}
Teraz próbujemy go modyfikować:
interface SimpleInter {
a: number;
b: number;
}
//SimpleInter //"a"|"b" //number
function modifySimple(obj: SimpleInter, key: keyof SimpleInter, val: SimpleInter[keyof SimpleInter]){
obj[key] = val;
}
Na razie żadnych błędów. Ok, teraz dodajmy jakiś inny typ do niego:
interface SimpleInter {
a: number;
b: number;
c: string;
}
//SimpleInter //"a"|"b"|"c" //string|number
function modifySimple(obj: SimpleInter, key: keyof SimpleInter, val: SimpleInter[keyof SimpleInter]){
obj[key] = val; //err
}
//Type 'string | number' is not assignable to type 'never'.
Ok, jak z tego wybrnąć? Możemy użyć typu generycznego:
interface SimpleInter {
a: number;
b: number;
c: string;
}
function modifySimple<T extends SimpleInter, K extends keyof T>
(obj: T, key: K, val: T[K]){
obj[key] = val;
}
Ok, a teraz nieco inne podejście, czyli niemutowalność. Taki interfejsik:
interface User1 {
name: string;
age: number;
isMarried: boolean;
};
Obiekt tego interfejsu:
let jane1: User1 = {
name: "Jane",
age: 30,
isMarried: true
}
Funkcja zmieniająca ten obiekt:
function changeUser(usrOld: User1, newFields: Partial<User1>): User1 {
return {...usrOld, ...newFields};
}
Całość:
interface User1 {
name: string;
age: number;
isMarried: boolean;
};
let jane1: User1 = {
name: "Jane",
age: 30,
isMarried: true
}
function changeUser(usrOld: User1, newFields: Partial<User1>): User1 {
return {...usrOld, ...newFields};
}
jane1 = changeUser(jane1, {isMarried: false});
console.log(jane1);
//{ name: 'Jane', age: 30, isMarried: false }
Ok, teraz generyczny odpowiednik:
interface User1 {
name: string;
age: number;
isMarried: boolean;
};
let jane1: User1 = {
name: "Jane",
age: 30,
isMarried: true
}
function changeUser(usrOld: User1, newFields: Partial<User1>): User1 {
return {...usrOld, ...newFields};
}
function changeObject<T extends object>(obj: T, newFields: Partial<T>) : T {
return {...obj, ...newFields}
}
// jane1 = changeUser(jane1, {isMarried: false});
jane1 = changeObject(jane1, {isMarried: false});
console.log(jane1);
//{ name: 'Jane', age: 30, isMarried: false }
Może i nie przesadnie trudne, ale takie ćwiczenia trzeba rozwiązywać. Wtedy dopiero wychodzi, ile wiemy, a ile nam się jeszcze miesza.
Do następnego razu!