TypeScript - 从通用联合类型缩小类型

2024-02-02

//Type declaration:

interface TickListFilter {
   type: "tickList";
   value: string;
}

interface ColorFilter {
   type: "color"
   value: ColorValueType
}

type Filter = TickListFilter | ColorFilter;



...
onValueChange = (filter: Filter, newValue: Filter["value"]) => {
        if (filter.type === "tickList") {
            // variable 'filter' has TickListFilter type (OK)
            // variable 'filter.value' has string type (OK)
            // variable newValue has ColorValueType | string. I know why, let's fix it!
        }
...

onValueChange = <T extends Filter>(filter: T, newValue: T["value"]) => {
        if (filter.type === "tickList") {
            // variable 'filter' has Filter type (wrong... i need tick list)
            // variable 'filter.value' has string | ColorValueType type (wrong, it should be string)
            // variable newValue has ColorValueType | string.
        }

我该如何解决这个问题?我知道为什么会发生这种情况,因为 TS 无法通过泛型类型区分联合。但是有没有像我所描述的那样有任何解决方法呢?

我想使用与 switch-case 类似的结构(不仅仅是 if-else)


啊,欢迎来到微软/TypeScript#13995 https://github.com/microsoft/TypeScript/issues/13995 and 微软/TypeScript#24085 https://github.com/microsoft/TypeScript/issues/24085。目前,编译器不使用控制流分析来缩小泛型类型参数或依赖于泛型类型参数的类型值的范围。从技术上讲,缩小类型参数本身是错误的,因为有人可以通过这种方式调用通用版本:

const filter: Filter = Math.random() < 0.5 ?
  { type: "tickList", value: "str" } : { type: "color", value: colorValue };
const newValue: string | ColorValueType = Math.random() < 0.5 ? "str" : colorValue;
onValueChange(filter, newValue); // no compiler error
// const onValueChange: <Filter>(filter: Filter, newValue: string | ColorValueType) => void

编译器会推断Filter for T,根据通用签名,这是“正确的”,但它会导致与非通用版本相同的问题。在函数内部可能是这样的newValue不匹配filter. ????


上述 GitHub 问题中已经有许多关于处理此问题的建议和讨论。如果像微软/TypeScript#27808 https://github.com/microsoft/TypeScript/issues/27808,你可以这样说T extends-exactly-one-member--of Filter意思是T可能TickListFilter or ColorFilter但它可以not be Filter。但现在还没有办法说这个。


目前最简单的方法是继续(假设您不想实际检查函数的实现内部filter and newValue彼此匹配)将涉及类型断言 https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions或类似的东西。您需要充分放松类型检查以允许代码,并且只是期望/希望没有人会像我上面那样调用您的函数。

这是使用类型断言的一种方法:

const onValueChange = <T extends Filter>(filter: T, newValue: T["value"]) => {
  const f: Filter = filter; // widen to concrete type
  if (filter.type === "tickList") {
    const v = newValue as TickListFilter["value"]; // technically unsafe narrowing
    f.value = v; // okay
  } else {
    const v = newValue as ColorFilter["value"]; // technically unsafe narrowing
    f.value = v; // okay
  }
}

Playground 代码链接 https://www.typescriptlang.org/play/#code/PTAqE8AcFMAIBNoGMA2BDATmgLgSwPYB2AXAFC6HbQYBmaScouSA1gDK4DO2AYrilQywA3qVixsUaMVgAiPKw7dZAbjGwAbmhQBXabG4YKAczUBfUuUrU6DWAGF8KfBj4DqI9ZJgzZSJy6y6lq6+o7OGABq2noQMKQWpN5w4S7RoXFwALwisP4RMoYmsGZq-oTceQFRMWHV6bFSsDnCVQVyaACOOmgAtpgU0LIlaklNboLNsEyKXLz8kwA+DtUT1KPllUQN0PYAFmiExtmwADygsNAAHlSE8JywaxgAfAAUNAvUMqAANLCE0AA7jtvgBtWQhPSyAC6AEpms9POJNthYDQZE8ph93BgVLAQLBAbhEIQJPgqoQkBhoFQJFJ1LgaLB3p8MAA6ZLNLI5eTMdhzWTw0TiZFESoaKYA4G1WBoB4zfncJ7gyFDaF4glUJB7QjMbQocCwHQVNA0OCETAYfBEo7qcQ0NmqqYaDXAWD4FhocDqMyXFCcODCkUozSSoE7WUPVKuVkq2ow10SZA6vUoA1Gk1m-6W60mNQitGOmU5F34t0er0+hKWEPYwQY1lTACyOD2bKwd3wvVe8NOsAADGyAKywAD86layV8CkV2Fkf1VvkMw19MknUl8+UCC9qMi3NVCI1IIalIIM2CMR1gy2jO0yzdb7cO8C7PbOA+HY7ky9ge-qtTUbZan2Q5jhZHE-lPWpYUTQhyX8XpIH4DxqCtDBSAJEMgNCECjn0U4njeOsvkeVlIPDXdz0vYxrxWCI7ykeEskRDR8GJSwgA

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

TypeScript - 从通用联合类型缩小类型 的相关文章

随机推荐

  • Android 中的 Google 地图上的标记闪烁

    我刚刚开始Android应用程序开发 按照本教程开发了Google地图应用程序并在Google地图上添加了标记 http mobiforge com developing story using google maps android ht
  • 获取用户头像大小的照片

    我正在使用 C 开发 Facebook 网站应用程序 我可以使用以下方式获取信息 FacebookClient FBApp new FacebookClient getAccessToken dynamic user FBApp Get m
  • g++编译错误

    我是 Ubuntu 的新手 我尝试编写一个简单的 Hello World Ubuntu 11 04 中的 c 代码 该代码 在终端中 gcc Wall W Werror tex cpp o tex 但编译器返回了很多错误 tmp ccL8c
  • 用于本地化的流畅 NHibernate 映射

    我正在尝试从 NHibernate 映射构建数据库 但遇到了问题 我有许多具有本地化字符串值的类 public class MyClass1 public virtual int Id get set public virtual Shor
  • 如何创建私有类方法?

    这种创建私有类方法的方法是如何工作的 class Person def self get name persons name end class lt lt self private def persons name Sam end end
  • Dart 异常:已经为元素 x 注册了(聚合物)原型

    我有两个共享相同飞镖文件的聚合物元件 在 dart 文件中 我声明了两个 PolymerElement 类 直到聚合物 0 15 0 1 都工作正常 我已将项目更新为聚合物 0 15 1 现在出现此异常 Exception Already
  • 函数参数过多

    我从我的头文件中收到此错误 too many arguments to function void printCandidateReport 我对 C 相当陌生 只需要一些正确方向的指导来解决此错误 我的头文件如下所示 ifndef CAN
  • 如何在`Axios.interceptors.request`的配置中获取Cookies的`csrftoken`?

    我怎样才能得到饼干csrftoken in Axios interceptors request的配置 Axios interceptors request use config gt if config method post confi
  • 使用 GWT 编译器将 Java 转换为 JavaScript

    我写了一些 Java 代码 想将其转换为 JavaScript 我想知道是否可以使用GWT编译器将提到的Java代码编译为JavaScript代码保留所有名字方法 变量和参数 我尝试使用 draftCompile 关闭代码优化来编译它 但方
  • 以明文显示的 IIS 应用程序池身份帐户密码

    当我使用appcmd list apppool
  • 删除时触发将行插入到另一个表中

    我正在尝试创建一个触发器 它将包含所有列的行插入到另一个表中 这是我到目前为止所得到的 但它不起作用 delimiter CREATE TRIGGER item deleted move AFTER DELETE ON item begin
  • 在php中将时间戳转换为之前的时间?

    我知道这个问题已经被问过好几次了 我发现了很多关于在 php 中将时间戳转换为之前时间的教程 博客文章 我尝试了无数的代码 但似乎没有什么对我有用 我要么得到一个没有错误的空白页面 我的 php 页面上重新发布时出错 要么在我的页面中得到一
  • 如何在 Flutter 上使用 SignalR?

    我正在尝试与使用 SignalR 建立聊天通信的 Asp Net core 2 1 应用程序进行通信 但我无法弄清楚使用 flutter 实现这一目标的最佳方法是什么 我已经搜索了一些库来做到这一点 但我发现的库与 Flutter 不兼容
  • 避免多个ajax请求

    我试图避免向工厂中的服务器发出多个 ajax 请求 我已经添加了一个小型缓存服务 但这还不足以实现我的目标 在服务器响应之前可以多次调用该工厂 从而导致向服务器生成多个请求 为了避免这种情况 我添加了第二个 Promise 对象 如果 AJ
  • 如何将两个 SSE 寄存器加在一起

    我有两个 SSE 寄存器 128 位是一个寄存器 我想将它们相加 我知道如何在其中添加相应的单词 例如我可以这样做 mm add epi16如果我在寄存器中使用 16 位字 但我想要的是类似的东西 mm add epi128 不存在 它将使
  • 重置索引后无法过滤索引列中包含特定值的行

    我正在组织多个计划的数据 其中包含计划阶段的信息 P 初步 或F 最终 我正在使用中显示的方法examples https pandas pydata org pandas docs stable generated pandas Data
  • 如何在react-leaflet中制作一个椭圆形?

    我正在尝试在使用制作的地图上绘制一个椭圆react leaflet 它内置了对圆形和矩形的支持 为了实现这一点 我使用代码在 非反应 中生成一个椭圆leaflet from here https github com jdfergason
  • 在移动设备上,执行其他操作几分钟后,localStorage 就会被删除

    仅当我在 iPhone 5S iOS 12 5 2 和 LG Android 手机上运行渐进式 React Web 应用程序时 才会出现此问题 它通过 Mobile Chrome 和 Mobile Safari 来实现此目的 我的 Macb
  • 如何生成与数据库记录匹配的唯一 URL 变量?

    我希望能够生成这样的 URL 变量 http example com 195yq http example com 195yp http example com 195yg http example com 195yf 这些变量将与 MyS
  • TypeScript - 从通用联合类型缩小类型

    Type declaration interface TickListFilter type tickList value string interface ColorFilter type color value ColorValueTy