为什么TS中的通用接口不能正确推断类型?

2024-05-25

一旦“延长Explicit_value” 在泛型接口中使用时,TS 的类型系统会变得“愚蠢”,即使代码“100%正确”。

function fn<T extends "a" | "b">(param: T): T {
    if (param === "a") return "a"/* <-- error
Type '"a"' is not assignable to type 'T'.
  '"a"' is assignable to the constraint of type 'T',
  but 'T' could be instantiated with a different subtype of constraint '"a" | "b"'.
 */
    else return "b"/* <-- error
Type '"b"' is not assignable to type 'T'.
  '"b"' is assignable to the constraint of type 'T',
  but 'T' could be instantiated with a different subtype of constraint '"a" | "b"'.
 */
}

//that's ok:
function fn2<T extends string>(param: T): T {
    return param
}

//even this:
function fn3<T extends "a">(): T {
    return "a"/* <-- error
Type '"a"' is not assignable to type 'T'.
  '"a"' is assignable to the constraint of type 'T',
  but 'T' could be instantiated with a different subtype of constraint '"a"'.
 */
}

我不会说这是愚蠢的。只是安全而已。 考虑这个例子:

function fn3<T extends "a">(): T {
  return "a" // error

}

const result = fn3<'a' & { tag: 2 }>().tag // 2

代表着T延伸a但不等于“a”。 在上面的例子中,result is 2但在运行时它等于undefined.

这就是 TS 给你一个错误的原因。通用参数应与运行时值绑定。就像您在第二个示例中所做的那样。

让我们看一下您的第一个示例:

function fn<T extends "a" | "b">(param: T): T {
  if (param === "a") return "a"
  else return "b"

}


错误:

'"a"' 可分配给类型 'T' 的约束,但 'T' 可以使用约束 '"a" | 的不同子类型来实例化。 “b”'

请记住,这并不意味着T总是等于a or b. T可以是该约束/联合的任何子类型。 例如,您可以使用never这是类型系统的底层类型:

const throwError = () => {
  throw Error('Hello')
}

fn<'a' | 'b'>(throwError())

有没有机会fn将返回a or b?不,它会抛出错误。也许这不是最好的例子,只是想向您展示不同子类型的含义。

我们打电话吧fn具有不同的子类型集:

declare var a: 'a' & { tag: 'hello' }

const result = fn(a).tag // undefined

你可能会说:嘿,你不遵守规则。类型'a' & { tag: 'hello' }在运行时是无法表示的。事实上并非如此。tag一直会undefined在运行时。 但是,我们处于类型范围内。我们可以很容易地创建这样的类型。

SUMMARY

请不要治疗extends作为一个等号运算符。这只是意味着T可能是已定义约束的任何子类型。

P.S.TypeScript 中的类型是不可变的。这意味着一旦你创建了类型T由于某些限制,您无法返回相同的通用参数T与其他约束。我的意思是,在你的第一个例子中,返回类型T不能只是a或仅b。它将永远是a | b

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么TS中的通用接口不能正确推断类型? 的相关文章

随机推荐

  • REST api 可以通过两个 HTTP 方法公开吗?

    问题是我们有一个复杂的搜索 api 查询字符串 并且希望让用户可以方便地使用 body 所以我们希望同时允许 GET 和 POST 或 PUT 我知道 对于搜索是否为只读操作存在争论 并且根据 REST 标准 它应该只能是 GET 据我了解
  • 将 ObjectId 字段正确映射到字符串

    我正在对 RDBMS 世界进行一些探索 进入 MongoDB 的神秘海洋 我正在使用 Spring Data 来帮助我进行冒险 我需要在两个集合中的文档之间创建手动引用 我读到 DBRef 很昂贵 我的 pojo 是这样的 public c
  • 皮纳克斯还活着吗?

    我见过Pinax http pinaxproject com 过去我想用它 今天我想用它 它的版本是0 7 我想知道它是否仍在开发中 它非常有活力 正如你可以看到的GitHub 存储库 http github com pinax pinax
  • 为什么 Azure IoT 中心中有主键和辅助键?

    在 Azure IoT 中心创建共享访问策略或注册设备时 将生成主密钥和辅助密钥对 我注意到我可以使用主键或辅助键将设备连接到 IoT 中心 那么 拥有主键 辅助键的目的是什么 我应该如何设计这两个键的使用 主键和辅助键的目标有两个 首先
  • Maven/Junit 并行执行 - Cucumber-JVM v4.0.0

    我正在努力获取与 JUnit Maven 一起使用的 Cucumber JVM v4 0 0 的新并行执行功能 作为指定here https github com cucumber cucumber jvm tree v4 0 0 juni
  • 效率。函数返回值与输出参数

    函数返回值与 输出 参数 哪一个更快 我想我最好用我目前正在做的事情来解释 specify identifier and return pointer SceneNode createSceneNode const String desir
  • 如何使 superfish 下拉菜单响应式?

    我正在使用带有骨架框架的 superfish 下拉菜单 我希望它也能在手机上运行 默认情况下 它显示下拉项目 但它将鼠标悬停在其下方的项目上 我想以某种方式拥有它 以便它将父项推到它下面 有什么解决办法吗 这是一个更好的答案 我能够将 Su
  • Powershell,从txt文件读取并格式化数据(删除行,删除之间的空格)

    我对 powershell 真的很陌生 我想使用powershell读取txt文件并将其更改为其他格式 从 txt 文件中读取 设置数据格式 删除行 删除之间的空格 记录计数 T 000000002 9 个字符 然后将输出写入新文件 我两天
  • 使用 arrayWithCapacity 有什么好处

    arrayWithCapacity是一个定义在NSArray h并实施于NSArray m 当我查看代码时GNUStep https raw githubusercontent com gnustep gnustep base master
  • 颠倒句子中的“英语”单词

    我有一个字符串 其中可能使用多种语言 例如 and this is in English this is going to be continued 我只想反转英语单词 所以结果应该是这样的 English in is this and c
  • 如何使用 CamanJS 更改图像?

    我有多个图像 我想将它们加载到单个图像中
  • 如何在r中找到按业务分组的第二高薪水

    我想要的是每个企业的输出应该只包含第二高的工资条目 例如 customer id name sales firstname lastname income business 6 Priyank Dwivedi 2 Priyank Dwive
  • ReactJs 中输出事件的 Angular

    我正在寻找在 ReactJs 中创建类似 Angular 等输出事件的方法 我正在根据 Atomic 设计在 ReactJs 中制作一个组件库 因此 例如 我在其他组件中注入了一个 Button 我想知道如何为 Button 编写一个 pr
  • Jpa 复合键可为空列

    我正在使用 Hibernate 的 JPA impl 来对一些表进行建模 我在映射表时遇到问题 没有主键 在 4 列上有唯一索引 其中 3 列可以为空 我尝试破解它并将索引定义为复合 Id 但由于某些列可为空 因此无法正常工作 JPA Hi
  • 在系统进程中调用方法没有合格的用户错误

    我在 android 4 4 中使用通知侦听器服务 遇到一个错误 导致我的应用程序停止获取发布的通知 这是相当随机的 但当它发生时我看到 12 31 01 40 44 080 21680 21680 W ContextImpl Callin
  • C# - 迭代多个数组/列表的最有效方法

    我有五个不同长度的数组 我需要迭代所有这些数组 生成所有可能的内容组合 我目前正在使用 5 个嵌套的 for 循环 如下所示 for int a 1 a lt Array1 Length 1 a for int b 1 b lt Array
  • 如何仅对最新合并后的提交进行变基?

    考虑以下场景 我从master那里检查了一个分支 我做了一些承诺 我合并了更新的master 我做了更多的承诺 现在我想要从第 4 点开始变基提交 以便从第 2 点开始的提交不受影响 所以如果我最初有 1 2 x x x x x x x m
  • JSTL 1.2 标签参考文档的链接 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在 JavaEE 6 中 JSTL 版本是 1 2 我正在尝试找到此版本的 taglib 文档的链接 我
  • Spring MVC 重定向到特定 url 的 jsp

    我正在将 Spring MVC 用于 AngularJS 项目 我从前缀为 rest 的 url 提供 JSON 服务 所有jsp文件都是直接访问的 路由是使用Angular js处理的 我需要在访问 jsp 文件之前进行自定义验证 对于其
  • 为什么TS中的通用接口不能正确推断类型?

    一旦 延长Explicit value 在泛型接口中使用时 TS 的类型系统会变得 愚蠢 即使代码 100 正确 function fn