Typescript 编译时同类型约束
Typescript compile-time same-type constraint
这是一个简短的例子:
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!
我有什么
如果您尝试将 ChildA
与 ChildB
进行比较,它会抛出 TypeError
.
我想要的
我想静态地防止在不同 类 之间使用 equals 方法。如果不允许我在源代码中比较苹果和橘子,那么我就不需要在 运行 时间抛出错误! (又少考写了)
请注意,Mid
会像 Entity
一样非常笼统,而 Child
类 会像客户、订单等。 - 具有商业意义的事物。将 Customers 与 Orders 进行比较是没有意义的,因此我想通过类型在源代码中展示这一点(毕竟,在我看来,这就是使用 TypeScript 的全部意义)。
问题
- 我怎样才能做到这一点?
- 我应该实现这个目标吗?也许我不需要担心开发人员(包括我自己)做傻事?
您可以限制参数派生自您正在访问的变量类型 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
由于 Typescript 使用结构类型,如果 ChildA
和 ChildB
具有相同的结构,上面的代码将不会阻止您调用 equals
但只要 ChildA
和ChildB
在结构上不兼容,你会得到一个错误。
关于你问题的第二部分,你应该评估天气这会带来更多的悲伤十个好处,这似乎是一个很好的限制,但你应该看看它在实践中的效果。
这是一个简短的例子:
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!
我有什么
如果您尝试将 ChildA
与 ChildB
进行比较,它会抛出 TypeError
.
我想要的
我想静态地防止在不同 类 之间使用 equals 方法。如果不允许我在源代码中比较苹果和橘子,那么我就不需要在 运行 时间抛出错误! (又少考写了)
请注意,Mid
会像 Entity
一样非常笼统,而 Child
类 会像客户、订单等。 - 具有商业意义的事物。将 Customers 与 Orders 进行比较是没有意义的,因此我想通过类型在源代码中展示这一点(毕竟,在我看来,这就是使用 TypeScript 的全部意义)。
问题
- 我怎样才能做到这一点?
- 我应该实现这个目标吗?也许我不需要担心开发人员(包括我自己)做傻事?
您可以限制参数派生自您正在访问的变量类型 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
由于 Typescript 使用结构类型,如果 ChildA
和 ChildB
具有相同的结构,上面的代码将不会阻止您调用 equals
但只要 ChildA
和ChildB
在结构上不兼容,你会得到一个错误。
关于你问题的第二部分,你应该评估天气这会带来更多的悲伤十个好处,这似乎是一个很好的限制,但你应该看看它在实践中的效果。