Typescript: Hur filtrerar du ett typs egenskaper till de av en viss typ?
Jag har ett gränssnitt
export interface MyInterface {
a: number;
b: string;
c: number;
}
Jag vill skapa en bokstavlig typ av egenskapsnamnen för vilka värdet är av typen number
Jag vet hur man får typen med alla egenskapsnamn med hjälp av
type MyType = keyof MyInterface // gives 'a'|'b'|'c'
Jag vill få bara 'a'|'c'
Svar #1
Du kan verkligen definiera en sådan typ i TypeScript:
type KeysMatching<T extends object, V> = {
[K in keyof T]-?: T[K] extends V ? K : never
}[keyof T];
type MyType = KeysMatching<MyInterface, number>;
// type MyType = "a" | "c"
I detta returnerar KeysMatching<T, V> mängden nycklar i T vars egenskaper kan tilldelas V. Den använder en konditionell och mappad typ tillsammans med en egenskapsuppslagning. För varje nyckel K i keyof T kontrollerar den om T[K] kan tilldelas V. Om så är fallet returnerar den nyckeln K; om inte, returnerar den never. Så för dina typer skulle det vara något i stil med {a: "a", b: never, c: "c"}. Sedan slår vi upp egenskapsvärdena och får en union av typerna som "a" | never | "c" vilket reduceras till "a" | "c", precis som du ville.
Observera att KeysMatching<T, V> endast returnerar de egenskapsnycklar vars värden matchar V när man läser egenskapen. De som är exakt V eller en underordnad typ av V:
interface AnotherInterface {
narrower: 1;
exact: number;
wider: string | number;
}
type AnotherType = KeysMatching<AnotherInterface, number>;
// type AnotherType = "narrower" | "exact"
Om du vill få nycklarna som matchar V när du skriver en egenskap av T... det vill säga, exakt V eller en supertyp av V, då behöver du en annan implementation av KeysMatching:
type KeysMatchingWrite<T extends object, V> = {
[K in keyof T]-?: [V] extends [T[K]] ? K : never
}[keyof T];
type AnotherTypeWrite = KeysMatchingWrite<AnotherInterface, number>;
// type AnotherTypeWrite = "exact" | "wider"
Hur som helst, hoppas det hjälper. Lycka till!
Länk till kod
