Gibt es eine sauberere Möglichkeit, Konstruktorargumente und Instanzeigenschaften einer Klasse in Typescript zu definieren?


Cubabit

Derzeit definiere ich die Konstruktorargumente und Instanzeigenschaften meiner Typescript-Klassen wie folgt:

interface ConstructorProps {
  foo: number;
  bar: string;
  baz: boolean;
}

class MyClass {
  foo: number;
  bar: string;
  baz: boolean;

  constructor (props: ConstructorProps) {
    this.foo = props.foo;
    this.bar = props.bar;
    this.baz = props.baz;
  }
}

Welches ist ziemlich repetitiv. Gibt es eine Möglichkeit, dies sauberer zu machen, auch wenn dies nur für die Schnittstellen- und Instanzeigenschaften gilt?

Tizian Cernicova-Dragomir

Mit zugeordneten Typen und bedingten Typen können wir einen Typ erstellen, der alle Felder einer Klasse enthält, und ihn als Konstruktorargument verwenden. Wir können auch Object.assigndie Eigenschaften kopieren, anstatt jedes Feld zuzuweisen:

type NotMethods<T> = { [P in keyof T]: T[P] extends (...args: any[]) => any ? never: P }[keyof T];
type Fields<T> = { [P in NotMethods<T>]: T[P] }

class MyClass {
    foo: number;
    bar: string;
    baz: boolean;

    constructor(props: Fields<MyClass>) {
        Object.assign(this, props)
    }


    method() {

    }
}

new MyClass({
    foo: 1,
    bar: '',
    baz: true
});

Spielplatz Link

Der FieldsTyp kann für jede Klasse wiederverwendet werden. Alle Felder der Klasse werden im Konstruktorargument benötigt.

Wenn Sie optionale Felder haben und strenge Nullprüfungen verwenden , können Sie eine Version schreiben, die die Optionalität des Felds im Konstruktorparameter beibehält:

type NotMethods<T> = Exclude<{ [P in keyof T]: T[P] extends (...args: any[]) => any ? never: P }[keyof T], undefined>;
type FilterUndefined<T, TKeys extends keyof T = keyof T> = Exclude<{ [P in TKeys]: undefined extends T[P] ? never: P }[TKeys], undefined>;
type KeepUndefined<T, TKeys extends keyof T = keyof T> = Exclude<TKeys, FilterUndefined<T, TKeys> | undefined>

type Fields<T> = { [P in FilterUndefined<T, NotMethods<T>>]: T[P] } & { [P in KeepUndefined<T, NotMethods<T>>]?: T[P] }

class MyClass {
    foo: number;
    bar: string;
    baz?: boolean;

    constructor(props: Fields<MyClass>) {
        Object.assign(this, props)
        props.foo
    }

    method() {

    }
}

new MyClass({
    foo: 1,
    bar: '',
    baz: true
});

new MyClass({
    foo: 1,
    bar: '',
});

Spielplatz Link

Verwandte Artikel