typescript - Kako mogu dobiti zajedničke tipove u nizu
Imam strukturu
interface T1<T extends string> {
path: T,
handler: (value: T) => void
};
ako koristim funkciju s istim sučeljem nemam problema s tipovima, sve je ispravno
declare function foo1<T extends string>({ path, handler }: T1<T>): void
const handlerWithoutError = (v: 'some_path') => { }
foo1({ path: 'some_path', handler: handlerWithoutError })
const handlerWithError = (v: 'wrong_path') => { }
foo1({ path: 'other_path', handler: handlerWithError })
ali ako pokušam koristiti niz umjesto očitog sučelja, tip radi na pogrešan način
declare function boo1<T extends string>(arr: T1<T>[]): void
boo1([
{ path: 'some_path', handler: handlerWithoutError },
{ path: 'other_path', handler: handlerWithError },
])
Trebam da parametar funkcije "handler" odgovara "path" za svaki element niza zasebno. Za drugi element to bi trebala biti greška, dok prvi nije. Kako riješiti taj problem i natjerati TS da prikazuje ispravne savjete? Playground
Odgovor #1
Predložio bih da koristite sljedeći potpis poziva:
declare function boo1<T extends string[]>(
arr: [...{ [I in keyof T]: T1<T[I]> }]
): void
Funkcija je generička u parametrima tipa T koji odgovaraju tuple tipu argumenata u foo1(). Tada je arr tipa mapiranog tuple-a {[I in keyof T]: T1<T[I]> } koji pretvara T u verziju gdje je svaki element omotan s T1<>. Pa, većinom tog tipa; omotan je u varijabilnom tuple tipu [...+] da bi se kompajleru dala naznaka da želite da se tip arr-a iščita kao tuple, a ne kao nesortiran niz proizvoljne duljine.
Pogledajmo što se događa kada ga pozoveš:
declare const x: T1<"a">;
declare const y: T1<"b">;
declare const z: T1<"c">;
boo1([x, y, z]); // okay
// function boo1<["a", "b", "c"]>(arr: [T1<"a">, T1<"b">, T1<"c">]): void
Argument arr je [x, y, z]. To se zaključuje da je tipa tuple [T1<"a">, T1<"b">, T1<"c">] (zbog varijabilnog tuple [...+] u potpisu poziva; usporedite s onim što se događa ako ga ne koristite). Zatim kompajler može zaključiti T iz mapiranog tipa { [I in keyof T]: T1<T[I]> } kao ["a", "b", "c"]. I s obzirom na tu zaključivanju, poziv prolazi provjeru tipa uspješno.
Pogledajmo što se događa kada ga pozovete greškom:
boo1([
{ path: 'some_path', handler: handlerWithoutError }, // okay
{ path: 'other_path', handler: handlerWithError }, // error!
// -----------------> ~~~~~~~
// Type '"other_path"' is not assignable to type '"wrong_path"'.
])
// function boo1<["some_path", "other_path"]>(
// arr: [T1<"some_path">, T1<"other_path">]): void
Ovdje kompajler izvodi T kao ["some_path", "other_path"] iz svojstava path. Što znači da arr treba biti tipa [T1<"some_path">, T1<"other_path">]. Prvi element arr-a je tipa T1<"some_path">, ali drugi element nije tipa T1<"other_path">, i stoga dobivate željenu pogrešku.
Igralište poveznica na kod
