Použít typescript dynamicky nastavit vlastnosti třídy v konstruktoru

0

Otázka

Já se snažím vytvořit strojopis třídy MyClass s vlastnosti instance dynamicky nastavuje v konstruktoru:

const myInstance = new MyClass(({
  someField: 'foo'
}))

myInstance.someField // typescript should show this as type string

Jak mohu použít typescript vytvořit MyClass ukázat someField jako řetězec vlastnost myInstance?

Mohu používat generika? Je to vůbec možné?

class dynamic generics typescript
2021-11-21 04:43:39
2

Nejlepší odpověď

1

Koncepčně chcete říct něco jako class MyClass<T extends object> extends T nebo class MyClass<T extends object> implements T, ale Strojopis nedovolí class stupni, nebo interface mít dynamické klíče. Všechny klíče z class nebo interface prohlášení musí být staticky známy. Takže pokud chcete toto chování budete muset udělat něco jiného, než class prohlášení.

Místo toho, můžete popsat typ požadované MyClass<T> instance, stejně jako typ MyClass konstruktoru třídy, a pak použít typ tvrzení říci kompilátoru, že vaše skutečné konstruktoru je objekt daného typu.

Představte si, že vaše zamýšlené MyClass<T> instance třídy mají všechny vlastnosti Tplus metoda jménem someMethodIGuess(). Pak se vaše MyClass<T> typ může být definován takto:

type MyClass<T extends object> = T & {
    someMethodIGuess(): void;
}

Chcete, aby vaše MyClass konstruktoru třídy mají vytvořit podpis , který bere jako argument typ T pro některé obecný T typ objektu, a vytváří instance MyClass<T>. To může být definován takto:

type MyClassConstructor = {
    new <T extends object>(arg: T): MyClass<T>
}

K provedení této třídy můžeme použít [Object.assign()] zkopírovat argument konstruktoru vlastnosti do instance, plus nějaké metody nebo jiné věci, které potřebujeme.

const MyClass = class MyClass {
    constructor(arg: any) {
        Object.assign(this, arg);
    }
    someMethodIGuess() {

    }
} 

Ale samozřejmě pokud bychom to takhle nechat, kompilátor nebude vidět MyClass jako MyClassConstructor (koneckonců, to nemůže mít dynamické klíče, a ani jsem se snaží říct, to o T zde). Potřebujeme typ tvrzení, říct to tak, jako tento:

const MyClass = class MyClass {
    constructor(arg: any) {
        Object.assign(this, arg);
    }
    someMethodIGuess() {

    }
} as MyClassConstructor;

Že se zkompiluje bez chyb. Znovu, všimněte si, že kompilátor je schopen pochopit, že MyClass provedení odpovídá MyClassConstructor typ. Pomocí typu tvrzení, jsem přesunula břemeno zajištění, že je správně implementován od kompilátoru (což nemůžu), aby mi (nebo vás, pokud budete používat tento kód). Takže bychom měli být velmi opatrní, aby zkontrolovat, co jsme udělali a že jsme to nenapsal špatně (např. Object.assign(arg, this); místo Object.assign(this, arg); by být problém).


Pojďme to vyzkoušet:

const myInstance = new MyClass(({
    someField: 'foo'
}))

console.log(myInstance.someField.toUpperCase()); // FOO
myInstance.someMethodIGuess(); // okay

Vypadá dobře! Kompilátor očekává myInstance mít someField vlastnost typ string, stejně jako, že someMethodIGuess() metoda.


Takže, to je to. Všimněte si, že tam jsou výhrady kolem pomocí MyClass stejným způsobem byste použít další konstruktoru třídy. Například kompilátor bude nikdy být šťastný s class prohlášení, že má dynamické klíče, takže pokud se budete snažit, aby generické podtřídy MyClass s class prohlášení, dostanete chybu:

class SubClass<T extends object> extends MyClass<T> { // error    
    anotherMethod() { }
}

Pokud potřebujete něco takového zjistíte sami museli použít stejný trik jako předtím s podtřídy:

type SubClass<T extends object> = MyClass<T> & { anotherMethod(): void };
type SubClassConstructor = { new <T extends object>(arg: T): SubClass<T> };
const SubClass = class SubClass extends MyClass<any> {
    anotherMethod() { }
} as SubClassConstructor;

Hřiště odkaz na kód

2021-11-22 00:19:33
0

Jak o tomhle?

class MyClass{
    constructor(props: any) {
        Object.assign(this, props);
    }

    baz(): string {
        return "Hello World";
    }

    static create<T>(props = {} as T) {
        return new MyClass(props || {}) as MyClass & T
    }
}

const o = MyClass.create({
    foo: 1,
    bar: "Hello World"
});

console.log(o.foo);
console.log(o.bar);
console.log(o.baz());


TS dětské hřiště

2021-11-21 10:59:11

Děkuji, ale já bych chtěl volat třídy s "nového" operátora. Takže to není práce pro mě. Ale znovu děkuji!
johann1301s

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................