generics - Typescript - Sužavanje T[K] u funkciji kada se proslijedi više vrijednosti ključa
Pokušavam napisati hook koji prihvaća više ključeva objekta i filtrira podatke na temelju trenutno primijenjenih filtera. Dakle, nešto u stilu ovoga:
interface IFilterable<T,K extends keyof T & string>{
key: K;
customFilter?: (item: T[K], applied: T[K][]) => boolean
//The hook uses some default logic to filter if this function isn't available.
}
function useFilters<T,K extends keyof T & string>(data: T[], filters: IFilterable<T,K>[]): T[]{
//filter out the data, return new dataset.
}
Problem je u tome što kada se proslijedi više filtara (IFilterable), parametri item i applied u funkciji customFilter postaju unija tipova ključeva. Ili, u kodu...
useFilters(
[{a: 1, b: "bob"], {a: 2, b: "berry"}],
[{key: "a", customFilter: (item, applied) => {
//Wanted: item has the type number
//Reality: item has the type (string | number)
},
{key: "b", customFilter: (item, applied) => {
//Wanted: item has the type string.
//Reality: item has the type (string | number)
}
}]);
Riješio sam problem tako da sam sve upisivao kao unknown (ili unknown[]), a zatim stvarao omotne funkcije koje kasnije vraćaju stvari na pravi tip, ali želim zadržati sve snažno tipizirano cijelim putem ako je moguće.
Dakle, postoji li na bilo koji način u slučajevima poput ovog, kada prosljeđujem niz objekata gdje je jedno svojstvo ključ, a drugo svojstvo funkcija koja prima T[K], da se suzi tip na određeni T[K] umjesto na uniju tipova?
Hvala.
Odgovor #1
AZURIRANJE 17. rujna 2021.
Napravio sam domaću zadaću.
Razmotrite ovaj primjer:
/**
* Obtain a union of all values of a dictionary
*/
type Values<T> = T[keyof T]
type FilterBuilder<T extends any[]> = Values<{
[Key in keyof T[number]]: {
key: Key,
customFilter: (item: T[number][Key], applied: T[number][Key][]) => void
}
}>
{
// type Test = {
// key: "a";
// customFilter: (item: 1, applied: 1[]) => void;
// } | {
// key: "b";
// customFilter: (item: "str", applied: "str"[]) => void;
// }
type Test = FilterBuilder<[{ a: 1, b: 'str' }]>
}
const withFilters = <
Item extends Record<PropertyKey, unknown>,
Items extends Item[],
>(data: [...Items]) => <
Filter extends FilterBuilder<Items>,
Filters extends Filter[],
>(filters: [...Filters]) => { }
const useFilters = withFilters([{ a: 1, b: "bob" }, { a: 2, b: "berry" }])
const result = useFilters(
[{
key: "a", customFilter: (item, applied) => { }
},
{
key: "b", customFilter: (item, applied) => { }
}]
);
Za TypeScript je teško zaključiti key objekta i odmah primijeniti taj tip na drugu svojinu istog objekta, barem u ovom slučaju.
Stoga sam upravo stvorio uniju svih dopuštenih parova key/customFilter filtara.
Igralište
Values - stvara uniju svih vrijednosti u strukturi podataka rječnika
GraditeljFiltra:
- iterira preko svakog ključa elemenata koji postoje u tupli
T. - stvara novi objekt za iterirani ključ s
keyicustomFiltersvojstvima. - Gdje je
customFilterfunkcija s dva argumenta:item- vrijednost iteriranog objekta,applied- niz vrijednosti iteriranog objekta
withFilters: je kurrirana funkcija. Očekuje tuple objekata za koje smo zainteresirani i vraća funkciju koja očekuje niz rezultata FilterBuilder. FilterBuilder jednostavno vraća diskriminirani unija svih dopuštenih stanja key/customFilter objekta.
