Typescript编译时同型约束

时间:2018-02-16 15:48:46

标签: typescript inheritance compile-time

这是一个简短的例子:

abstract class Base {
    private _id: number;

    protected set id(value: number) {
        this._id = value;
    }
    protected get id(): number {
        return this._id;
    }

}

abstract class Mid extends Base {
    equals(another: Mid) {
        if (this.constructor.name !== another.constructor.name) {
            throw TypeError(`Cannot compare ${this.constructor.name} to ${another.constructor.name}`);
        }
        return this.id === another.id;
    }
}

class ChildA extends Mid {
    constructor(public name: string) {
        super();
    }
}
class ChildB extends Mid {
    constructor(public name: string) {
        super();
    }
}

const a = new ChildA('Joe');
const b = new ChildB('John');

a.equals(b); // PREVENT!

我有什么

如果您尝试将ChildAChildB进行比较,则会引发TypeError

我想要什么

我想静态地阻止在不同类之间使用equals方法。如果我不允许在源代码中将Apples与Oranges进行比较,那么我不需要在运行时抛出错误! (也少写一个测试)

请注意Mid会像Entity那样非常笼统,而Child类会像Customer,Order等一样 - 具有商业意义的东西。将客户与订单进行比较是没有意义的,所以我想通过类型在源代码中显示(毕竟,在我看来,这是使用TypeScript的全部意义)。

问题

  1. 我怎样才能做到这一点?
  2. 我想要实现吗?也许我不需要担心开发人员(包括我自己)在做蠢事吗?

1 个答案:

答案 0 :(得分:0)

您可以通过以下方式约束要从您正在访问的变量类型equal派生的参数:

abstract class Mid extends Base {
    equals<T extends this>(another: T) {
        // ...
        return this.id === another.id;
    }
}

class ChildA extends Mid {
    private foo: string;
    constructor(public name: string) {
        super();
    }
}
class ChildAA extends ChildA {
    private foo2: string;
    constructor( name: string) {
        super(name);
    }
}
class ChildB extends Mid {
    private bar: string;
    constructor(public name: string) {
        super();
    }
}

const a = new ChildA('Joe');
const b = new ChildB('John');

a.equals(b); //Error
a.equals(new ChildAA(''));  // Works if you don't want this to work, use equals(another: this)  as the signature instead

由于如果ChildAChildB具有相同的结构,Typescript使用结构类型,上述代码不会阻止您调用equals,但只要ChildA和{{ChildB 1}}在结构上不兼容,你会收到错误。

关于你问题的第二部分,你应该评估天气,这会带来更多的悲伤十大好处,这似乎是一个很好的约束,但你应该看看它在实践中是如何运作的。