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

Relaterte artikler