首页 > 解决方案 > 在 Typescript 中定义类的更短方法?

问题描述

一个标准的类声明如下所示:

class Foo {
    a: string;
    b: string;

    constructor({ a, b }: { a: string, b: string }) {
        this.a = a;
        this.b = b;
    }
}

这需要你复制一个变量 4 次——一个类型两次!可能看起来没什么大不了的,但它为一个非常简单的任务创建了不必要的样板,并且对字符串文字有问题,因为它要求您在多个地方都有硬编码的字符串。

我发现唯一更简单的方法是使用接口:

interface Foo {
    a: string;
    b: string;
}

const getFoo = ({ a, b }: Foo): Foo => ({ a, b });

但是现在需要同时导出 getter 和接口,这有点倒退。

有没有我想念的更简单的方法?

我很想看到像 Dart 的初始化器这样的东西:

class Foo {
    String a;
    String b;

    Foo({ this.a, this.b });
}

更新:

受到其中一个答案的启发,采取了更实用的方法:

interface Test {
    a: string;
    b: string;
}

export function get<T>(params:T):T {
  return params;
}

get<Test>({ a: 'hello', b: 'world' });

不幸的是,它缺少默认值。

标签: typescripttypescript2.0

解决方案


避免这种样板的一种方法是将其重构为您自己的库函数(这可能需要使用类型断言来说服编译器不要抱怨)

function ifaceToCtor<T extends object>(): new (param: T) => T {
    return class {
        constructor(arg: any) {
            Object.assign(this, arg);
        }
    } as any;
}

然后,您无需创建普通类,而是定义一个接口并使用以下命令创建其构造函数ifaceToCtor

interface Foo { a: string, b: string };
const Foo = ifaceToCtor<Foo>(); // short!

您可以验证它是否有效:

const foo = new Foo({ a: "eh", b: "bee" });
console.log(foo.a); // eh
console.log(foo.b); // bee

这类似于您的“getter”想法,但这是一个真正的类(如果重要的话),用于Object.assign()避免属性名称的重复并允许将其隐藏到您不需要查看的某个库中。


同样,您可以使用ifaceToCtor扩展 nonce 超类来添加不属于构造函数参数的方法或其他道具:

class Bar extends ifaceToCtor<{ c: string, d: number }>() {
    method() {
        return this.c.toUpperCase() + " " + this.d.toFixed(2);
    }
}

const bar = new Bar({ c: "hello", d: 123.456 });
console.log(bar.method()); // HELLO 123.46

而且这个版本的优点是您要导出的是标准外观class,其中命名的接口和构造函数Bar被带入您的范围,而不需要第一个示例中的interface-and- const

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读