Få type som kun inneholder egne egenskaper i Typescript
Jeg har denne koden:
class TestClass {
readonly firstProperty: number;
readonly secondProperty: string;
constructor() {
this.firstProperty = 5;
this.secondProperty = 'test';
}
logProperties() {
console.log(this.firstProperty);
console.log(this.secondProperty);
}
}
const instance = new TestClass(),
instanceSpread = { ...instance, anotherProperty: 'hello' };
La oss nå anta at jeg vil bruke instanceSpread som argument for en funksjon. Hvordan bør jeg erklære typen dens? Å bruke TestClass & { anotherProperty: string } vil ikke fungere fordi instanceSpread ikke har TestClass-metoder. Jeg vet at jeg kan lage min egen type ved å kopiere TestClass-egenskapene og bruke den, men hvis TestClass i fremtiden får ytterligere 10 egenskaper, må jeg også endre typen min. Jeg leter etter noe som automatisk kan gjøre typeinference.
Svar #1
Har du vurdert «extends»? Kanskje jeg ikke forstår spørsmålet? Men jeg tror «extends» vil svare på spørsmålet ditt.
class TestClass {
readonly firstProperty: number;
readonly secondProperty: string;
constructor() {
this.firstProperty = 5;
this.secondProperty = 'test';
}
logProperties() {
console.log(this.firstProperty);
console.log(this.secondProperty);
}
}
class TestClassAdvanced extends TestClass {
anotherProperty = 'hello'
}
instance = new TestClass()
instanceSpread = new TestClassAdvanced()
Svar #2
Dette ser ikke mulig ut uten å gå ned til uttrykksnivået, siden bruk av spread-syntaksen er den eneste måten å få TypeScript til å respektere tellerbarhet av egenskaper. Som jcalz foreslo, kan du bruke typeof instanceSpread som typen, men en annen lignende idé ville være å bruke en funksjon, og ta returtypen som typen til en spread-instans:
const _enumerableTestClass = (t: TestClass) => ({ ...t });
type EnumerableTestClass = ReturnType<typeof _enumerableTestClass>;
EnumerableTestClass holder nå { firstProperty: number; secondProperty: string; }, akkurat det vi lette etter, og det fungerer for å annotere instanceSpread:
const instanceSpread: EnumerableTestClass & { anotherProperty: string } = {
...instance,
anotherProperty: "hello",
};
Lekeplass
Hvis klassens egenskaper aldri er funksjoner (og alle klassens metoder er definert på prototypen), kan du i teorien ganske enkelt filtrere ut funksjoner:
type FilterFuncs<T> = { [K in keyof T as T[K] extends (...args: any[]) => any ? never : K]: T[K] };
Dette, krysset med den tilleggsegenskapen, ser ut til å samsvare med typen til spreddet:
// okay
const instanceSpread: FilterFuncs<TestClass> & { anotherProperty: string } = { ...instance, anotherProperty: 'hello' };
Lekeplass
