在下面的TypeScript中,我得到了一些意想不到的东西:
class BaseNode<C> {
id = ''
}
class ContainerClass<T> {
nodes: Record<string, BaseNode<T>> = {};
addNode (node: BaseNode<T>) {
this.nodes[node.id] = node;
}
}
class ContextOne {
getLabel() { return 'one' }
}
class ContextTwo {
getVal() { return 2 }
}
class GenderNode extends BaseNode<ContextOne> {}
class HeightNode extends BaseNode<ContextTwo> {}
const container = new ContainerClass<ContextOne>()
const genderNode = new GenderNode()
const heightNode = new HeightNode()
container.addNode(genderNode)
container.addNode(heightNode) // THIS WORKS, BUT SHOULD NOT
container
的类型是ContainerClass<ContextOne>
,这意味着它的addNode
函数应该被限制为addNode(node: BaseNode<ContextOne>)
类型。但是,我传入heightNode = BaseNode<ContextTwo>
。
因此,container.addNode()
函数只接受与容器使用相同上下文的节点示例。
1条答案
按热度按时间iqjalb3h1#
TypeScript的类型系统是结构化的,而不是nominal。在TypeScript中,类型通过它们的 * 形状 * 或 * 结构 * 进行比较。因此,具有相同成员的两个对象类型被视为同一类型,即使它们具有不同的名称或在不同的位置声明。
在示例代码中,
BaseNode<C>
的类型为{id: string}
,它在结构上完全独立于generic类型参数C
。所以BaseNode<A>
和BaseNode<B>
都是{id: string}
,因此它们是相同的,不管A
和B
是什么。这将导致编译器接受所有具有不同名称的事物作为同一类型。参见相关的TS常见问题解答条目。如果您希望
GenderNode
和HeightNode
被视为不同的类型,那么BaseNode<C>
应该在结构上依赖于C
。有很多方法可以做到这一点;您应该做最适合您的用例的任何事情。但最简单的方法是将C
类型的成员添加到类型中:一旦你这样做了,你会看到预期的错误:
Playground链接到代码