De ce nu poate TypeScript să deducă tipul de retur al acestei funcții?
Încerc să scriu câteva funcții utilitare care clonează obiecte, dar modifică proprietăți profunde.
Iată un exemplu de versiune oarecum inutilă care doar înlocuiește o proprietate denumită a unui obiect cu o altă valoare care poate fi de un alt tip. Codul funcționează - înlocuiește proprietatea denumită cu noua valoare - dar dintr-un motiv oarecare TypeScript nu poate determina tipul obiectului creat și dă o eroare la compilare. De ce nu îi place asta lui TypeScript și cum pot să fac să funcționeze?
Aș putea defini în mod explicit tipul returnat - dar acest lucru devine stânjenitor cu versiunile acestei funcții care schimbă o proprietate la mai multe niveluri adâncime.
it('change type of input object', () => {
const cloneWith = <T extends Record<string, unknown>, A extends keyof T, V>(
i: T,
a: A,
value: V
) => ({
...i,
[a]: value,
});
const source = { name: 'bob', age: 90 };
const result = cloneWith(source, 'age', 'old!');
// This test passes
expect(result.age).to.equal('old!');
// But compile error - number and string have no overlap -
// on this line
if (result.age === 'old!') {
console.log('That person is old!');
}
});
Răspuns #1
Tipurile deduse pentru literalele de obiect create cu sintaxa spread nu sunt întotdeauna ideale, mai ales atunci când sunt implicate proprietăți calculate. În acest caz, T este intersectat cu o semnătură de index {[x: string]: V}, în timp ce Omit<T, A> & {[K in A]: V} ar avea mai mult sens (intersecția dintre T fără proprietatea A și un obiect separat cu cheia A și valoarea T).
Nu văd cum ai putea rezolva asta fără un tip de returnare explicit, dar dacă adaugi tipul de returnare, cel puțin tipurile corecte sunt deduse. Poate poți face ceva similar pentru celelalte versiuni ale funcției tale.
const cloneWith = <T, A extends keyof T, V>(
i: T,
a: A,
value: V
): Omit<T, A> & {[K in A]: V} => ({
...i,
[a]: value,
});
const source = { name: 'bob', age: 90 };
const result = cloneWith(source, 'age', 'old!');
type TestSource = typeof source.age // number
type TestResult = typeof result.age // string
Loc de joacă TypeScript
