如何解决为什么下面的 TypeScript 程序不会抛出类型错误?
interface Eq<A> {
eq(this: A,that: A): boolean;
};
class Pair<A> implements Eq<Pair<A>> {
constructor(public x: A,public y: A) {}
eq(this: Pair<A>,that: Pair<A>): boolean {
return this.x === that.x && this.y === that.y;
}
}
class Triple<A> implements Eq<Triple<A>> {
constructor(public x: A,public y: A,public z: A) {}
eq(this: Triple<A>,that: Triple<A>): boolean {
return this.x === that.x && this.y === that.y && this.z === that.z;
}
}
const eq = <A extends Eq<A>>(x: A,y: A): boolean => x.eq(y);
console.log(eq(new Pair(1,2),new Triple(1,2,3)));
console.log(eq(new Triple(1,3),new Pair(1,2)));
我原以为 TypeScript 编译器会抱怨最后两行,因为您不应该将 eq
函数应用于不同类型的两个值。但是,TypeScript 编译器不会为上述程序抛出任何类型错误。上面程序的结果是true
和false
。
为什么 TypeScript 编译器不会为上述程序抛出类型错误?我们怎样才能让它正确地捕捉到这些类型的错误?
解决方法
程序编译是因为 TypeScript 中使用了 structural subtyping(与其他编程语言中经常出现的名义子类型相反)。
请注意,您的 Triple
类是可以分配给 Pair
类型的变量的:
const p: Pair<number> = new Triple(1,2,3);
在您的示例中:
console.log(eq(new Pair(1,2),new Triple(1,3)));
console.log(eq(new Triple(1,3),new Pair(1,2)));
eq
的类型推断为:
const eq: <Pair<number>>(x: Pair<number>,y: Pair<number>) => boolean
如上所示,Triple
是类型为 Pair
的参数的有效参数,因此一切都可以编译干净。
您可以向类添加不同的私有字段以模拟名义子类型。在此特定示例中,您可以选择以下两个选项之一:
- 添加额外的标记字段
- 将
x
、y
、z
设为私有并提供 getter
见Can I force the TypeScript compiler to use nominal typing?
,首先我投票给@VLAZ 的评论。
由于 Pair 和 Triple 都实现了 Eq
,我相信这就是您没有编译错误的原因。
另外,根据@VLAZ 的评论,TS 不支持更高级的类型。
既然你使用的是 F 有界多态性,我相信你应该给 TS 一个关于第二个参数的提示。
interface Eq<A> {
eq(this: A,that: A): boolean;
};
class Pair<A> implements Eq<Pair<A>> {
constructor(public x: A,public y: A) { }
eq(this: Pair<A>,that: Pair<A>): boolean {
return this.x === that.x && this.y === that.y;
}
}
class Triple<A> implements Eq<Triple<A>> {
constructor(public x: A,public y: A,public z: A) { }
eq(this: Triple<A>,that: Triple<A>): boolean {
return this.x === that.x && this.y === that.y && this.z === that.z;
}
}
// hint is here :D
const eq = <Fst extends Eq<Fst>,Scd extends Eq<Scd> & Fst>(x: Fst,y: Scd): boolean => x.eq(y);
const x = eq(new Pair(1,3)); // ok
const y = eq(new Triple(1,2)); // error
这不是一个完整的答案,但我希望它能给你一些线索
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。