【问题标题】:TypeScript: Typing problem with "A extends B"TypeScript:“A 扩展 B”的打字问题
【发布时间】:2020-08-24 12:42:02
【问题描述】:

[编辑 - 结束语]:事实证明,下面的问题主要是一些次优类型的结果,通常你可能没有像我在我的程序中遇到的这样的问题 => 现在有了这些知识,我的问题确实似乎不再有意义(正如其他人在下面已经提到的那样)。


请看下面的 TypeScript 代码 sn-p。 作为B extends A,这条c: 8 当然是允许的。 如何更改function f 的类型以禁止ab 旁边的其他键?

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-A (with type error)

Demo-B (without type error)

但正如您在 Demo-B 中看到的那样,您现在可以将无效参数添加到组件配置中 - 这不是很好……这就是我提出上述问题的原因。

[编辑 - 稍后] 不是我上面问题的答案,但至少 Demo-B 的以下修改应该可以按需要工作:Demo-C

【问题讨论】:

  • "如何更改函数 f 的类型以禁止 a 和 b 旁边的其他键?"正是您要避免的。看来你真的需要function f(b: A)
  • @BunyaminCoskuner 感谢您的评论。我用一个更复杂的例子编辑了我上面的描述。也许这更能说明我的意思。
  • @BunyaminCoskuner 我认为你是对的,我在上面的 Demo-2 中使用泛型的方式没有太大意义。我已经相应地更新了上面的描述。感谢您的帮助。
  • 没问题。您的用例非常复杂。我认为你的问题太深了,你只需要走出去重新考虑一下:)

标签: typescript typescript-typings typescript-types


【解决方案1】:

行为是设计使然。 TS 是结构类型语言,其中类型兼容性基于子类型化,换句话说,每个具有所有约束的类型都将通过规则。在您的示例中,值的类型具有所需的所有字段,因此是“a”和“b”,因此一切正常。

您没有理由不允许传递此类对象,因为内部的其他字段不应使您有所作为。说你扩展意味着你被允许在像对象这样的复合方面拥有更多的字段。

如果您想要一个子类型,则附加,但不幸的是,唯一符合您需要的类型是A,因此函数签名应该是f(a: A)

需要明确的是,即使使用f(a: A),您也可以传递带有附加字段的值,只有对象字面量才会被严格验证。任何具有更多字段的赋值都可以使用而不会编译器抱怨。以及我已经描述的原因。

【讨论】:

  • 我希望得到类似:function f&lt;B extends A &amp; { [k: string]: never }&gt;(b: B): void { },请参阅:typescriptlang.org/play/…
  • 如果您不想要任何其他属性,那么您尝试做的事情对我来说没有意义@Natasha,为什么不直接使用f(b: A)?拥有泛型有什么意义?
  • @Maciej 非常感谢您的回复。请在上面的描述中找到一个更复杂的示例,希望能说明我的意思。
  • @MaciejSikora 也许你是对的,整个问题是关于一些滥用的泛型 - 我已经相应地更新了顶部的描述。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 2011-12-03
  • 2014-08-14
  • 1970-01-01
相关资源
最近更新 更多