TypeScript:"A extends B" 的输入问题
TypeScript: Typing problem with "A extends B"
[编辑 - 结束语]:事实证明,下面的问题主要是一些次优类型的结果,通常你可能不会像我在我的程序中那样遇到这样的问题=>现在有了这些知识,我的问题似乎不再有意义(正如其他人已经在下面提到的那样)。
请查看以下 TypeScript 代码片段。
作为 B extends A
这条 c: 8
行当然是允许的。
我如何更改 function f
的类型以禁止 a
和 b
旁边的其他键?
type A = { a: number, b: number }
function f<B extends A>(b: B): void {
}
f({
a: 3,
b: 4,
c: 8 // <- This shall cause a compile error
})
» Demo
PS:当然function f(b: A) {}
不是我要找的。这里的这个例子只是简化了,现实世界的用例要复杂得多...... function f
保持通用性很重要。
[编辑]:由于我上面的简化引起了一些混乱:
请在这里找到一个更复杂的例子,上面我的问题的答案可能会有所帮助(一个虚构的 UI 组件 API):
请查看Demo-A中的类型错误。这将在 Demo-B 中修复。
但是正如您在 Demo-B 中看到的那样,您现在可以向组件配置添加无效参数 - 这不是很好......这就是我提出上述问题的原因。
[编辑 - 稍后] 不是我上面问题的答案,但至少 Demo-B 的以下修改应该可以按预期工作:Demo-C
该行为是设计使然。 TS 是结构类型语言,其中类型兼容性基于子类型化,换句话说,具有所有约束的每个类型都将通过规则。在您的示例中,值类型包含所有需要的字段,因此 'a' 和 'b',因此一切正常。
您没有理由不允许传递此类对象,因为内部的附加字段不会让您有所作为。说你扩展意味着说你可以在像对象这样的组合方面拥有更多的领域。
如果您想要一个子类型,则附加,但不幸的是,对于精确字段,唯一符合您需要的类型将是 A
,因此函数签名应该是 f(a: A)
。
需要说明的是,即使使用 f(a: A)
,您也可以通过附加字段传递值,只有对象字面量会被严格验证。任何具有更多字段的赋值都可以使用而不会引起编译器的抱怨。原因我已经描述过了。
[编辑 - 结束语]:事实证明,下面的问题主要是一些次优类型的结果,通常你可能不会像我在我的程序中那样遇到这样的问题=>现在有了这些知识,我的问题似乎不再有意义(正如其他人已经在下面提到的那样)。
请查看以下 TypeScript 代码片段。
作为 B extends A
这条 c: 8
行当然是允许的。
我如何更改 function f
的类型以禁止 a
和 b
旁边的其他键?
type A = { a: number, b: number }
function f<B extends A>(b: B): void {
}
f({
a: 3,
b: 4,
c: 8 // <- This shall cause a compile error
})
» Demo
PS:当然function f(b: A) {}
不是我要找的。这里的这个例子只是简化了,现实世界的用例要复杂得多...... function f
保持通用性很重要。
[编辑]:由于我上面的简化引起了一些混乱: 请在这里找到一个更复杂的例子,上面我的问题的答案可能会有所帮助(一个虚构的 UI 组件 API):
请查看Demo-A中的类型错误。这将在 Demo-B 中修复。
但是正如您在 Demo-B 中看到的那样,您现在可以向组件配置添加无效参数 - 这不是很好......这就是我提出上述问题的原因。
[编辑 - 稍后] 不是我上面问题的答案,但至少 Demo-B 的以下修改应该可以按预期工作:Demo-C
该行为是设计使然。 TS 是结构类型语言,其中类型兼容性基于子类型化,换句话说,具有所有约束的每个类型都将通过规则。在您的示例中,值类型包含所有需要的字段,因此 'a' 和 'b',因此一切正常。
您没有理由不允许传递此类对象,因为内部的附加字段不会让您有所作为。说你扩展意味着说你可以在像对象这样的组合方面拥有更多的领域。
如果您想要一个子类型,则附加,但不幸的是,对于精确字段,唯一符合您需要的类型将是 A
,因此函数签名应该是 f(a: A)
。
需要说明的是,即使使用 f(a: A)
,您也可以通过附加字段传递值,只有对象字面量会被严格验证。任何具有更多字段的赋值都可以使用而不会引起编译器的抱怨。原因我已经描述过了。