Typescript få type som ekskluderer alle funksjoner fra en klasse
Jeg kopierer dataene fra en klasseinstans ved å bruke spread-operatoren: const myObj:MyType={...myClassInstance}, hvor myClassInstance er en instans av MyClass. Jeg ønsker å definere typen MyType, som utelukker alle funksjoner definert på MyClass, og beholder bare strenger, tall, arrays osv. Jeg prøvde dette:
type ExcludeSubType<Base, Condition> = Pick<Base, {
[Key in keyof Base]: Base[Key] extends Condition ? never : Key
}[keyof Base]>;
export type MyType = ExcludeSubType<MyClass, (_: any) => any>;
MyClass kan se omtrent slik ut:
export class MyClass {
foo: string;
constructor(foo: string) {
this.foo = foo;
}
stopTimer() {
// stuff
}
startTimer() {
// stuff
}
continue(p1: string, p2: number) {
// stuff
}
setFailed(p1: string, p2: string) {
// more stuff
}
}
Men MyType har fortsatt funksjoner på seg - spesielt funksjonene med argumenter. Hva gjør jeg feil?
Svar #1
export type MyType = ExcludeSubType<MyClass, Function>;Typen (_: any) => any samsvarer bare med funksjoner som tar høyst ett argument.
Svar #2
Titian har allerede gitt svaret, men jeg vil gjerne prøve å gi en mer utførlig forklaring.
Problemet er at du utelukker bare en svært spesifikk type funksjon - funksjonene som tar maksimalt ett argument, for å være spesifikk.
Relasjonen extends kan forstås som følger: hvis A extends B, så kan A tildeles til B. I ditt tilfelle betyr det at de utelukkede medlemmene alle må kunne tildeles til (_: any) => any, dvs. du kan sende dem noen steder hvor funksjoner med ett argument forventes.
Men, hvis funksjonen din tar to argumenter (slik setFailed gjør i eksemplet ditt), så kan du ikke sende den inn på et sted som forventer en funksjon med ett argument. Ellers ville noen kunne kalle funksjonen din uten å gi alt den forventer. Så, (typeof setFailed) extends (_: any) => any er falsk - denne funksjonen vil ikke bli ekskludert, som du allerede har bemerket.
Så, hvordan gjør man dette? Åpenbart bør du ekskludere alle funksjoner, uansett hvor mange argumenter de har. Det betyr at du trenger en type som enhver annen funksjonstype kan tilordnes. Og vi har to alternativer for dette, oppført i andre svar:
- Du kan enkelt bruke
Function-typen fra standardbiblioteket. Dette vil fungere, men denne typen kan være forbudt av noen linters som ikke eksplisitt. - Du kan bruke eksplisitt typing. Vi trenger å uttrykke det faktum at den (tenkte) funksjonen vi beskriver kan ta et vilkårlig stort antall argumenter. Det er akkurat i slike tilfeller vi kan bruke restparametere, ved å «samle» alle argumentene i tuplen:
(...args: any[]) => any.