为什么以“T extends undefined”为条件的 Typescript 类型(用“boolean”实例化 T)会将 T 解析为“never”?

2023-11-26

以下代码尝试定义当泛型参数为时不带参数调用的函数的类型undefined,但对于任何其他参数类型有 1 个参数。 (很可能有更好的方法来实现这一点,我很乐意在评论中看到链接,但问题是为什么 Typescript 的工作方式与我预期的不同。)

When T extends undefined是假的,T似乎变成never在 else 分支中,但仅在函数参数列表内...

type OptionalArgBroken<Arg> = Arg extends undefined ?
  () => void :
  (arg: Arg) => void;

const suppressArgBroken:OptionalArgBroken<undefined> = function() { };
suppressArgBroken(); // Fine

const haveArgBroken:OptionalArgBroken<boolean> = function(b:boolean) { };
haveArgBroken(true); // Type error

正如您在操场,上面的最后一行给出了类型错误

“true”类型的参数不可分配给“never”类型的参数。(2345)

看完之后https://github.com/microsoft/TypeScript/issues/31751,我尝试包裹Arg and undefined in []s,这似乎已经解决了问题:

type OptionalArgWorks<Arg> = [Arg] extends [undefined] ?
  () => void :
  (arg: Arg) => void;

const suppressArgWorks:OptionalArgWorks<undefined> = function() { };
suppressArgWorks(); // Fine

const haveArgWorks:OptionalArgWorks<boolean> = function(b:boolean) { };
haveArgWorks(true); // Fine

尽管该修复有效,但这不是同一个问题:

type MakesSenseT = undefined extends undefined ? 'yes' : 'no'
const MakesSense:MakesSenseT = 'yes';

type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'

const MakesSenseToo : ExtendsUndefined<undefined> = 'yes';
const MakesSenseThree : ExtendsUndefined<boolean> = 'no';

为什么我原来的代码不起作用?

上述代码的 Typescript Playground 链接


正如所写,

type OptionalArgBroken<Arg> = Arg extends undefined ?
    () => void :
    (arg: Arg) => void;

is a 分配条件类型因为正在检查的类型,Arg,是一个裸泛型类型参数。

“分布式”意味着如果Arg传入的是一个union,那么将分别评估联合体的每个成员的类型,然后重新组合在一起(因此操作是分散式整个联盟)。换句话说,OptionalArgBroken<A | B | C>将与以下相同OptionalArgBroken<A> | OptionalArgBroken<B> | OptionalArgBroken<C>.

这可能不是您的本意,您在签入时对结果感到满意就证明了这一点[](这使得检查类型不再通过“服装”来“裸体”)。


此外,TypeScript 编译器将boolean类型作为并集的简写true and false, 所谓的布尔文字类型:

type Bool = true | false;
// type Bool = boolean

如果您将鼠标悬停在Bool在带有 IntelliSense 的 IDE 中,您将看到Bool上面显示为boolean.

如果您想到这可能会感到惊讶boolean作为单一类型而不是其他两种类型的联合。当你经过时就会出现这种情况boolean分配条件类型:OptionalArgBroken<boolean> is OptionalArgBroken<true | false>这是OptionalArgBroken<true> | OptionalArgBroken<false>这是

type OABBool = OptionalArgBroken<boolean>;
// type OABBool = ((arg: false) => void) | ((arg: true) => void)

您传入了您认为是单一类型的内容,并得到了函数类型的联合。哎呀。 (看微软/TypeScript#37279)


并且函数类型的联合只能通过路口他们的参数。阅读关于支持调用函数联合的 TS3.3 发行说明有关原因的信息。

但这意味着类型的值OptionalArgBroken<boolean>只能使用类型参数来调用true & false,减少为never (see 微软/TypeScript#31838)因为不存在两者兼而有之的值true and false.

And 所以,当你尝试打电话时haveArgBroken,它期望传入的参数类型为never:

const haveArgBroken: OptionalArgBroken<boolean> = function (b: boolean) { };
// haveArgBroken(arg: never): void

And true不属于类型never,所以失败了:

haveArgBroken(true); // Type error

这就是为什么你的原始代码不起作用。


请注意,同样的事情也会发生

type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'

但这是良性的,因为ExtendsUndefined<boolean>变成ExtendsUndefined<true> | ExtendsUndefined<false>这是'no' | 'no'减少到只是'no'。它恰好是你想要的,但只是因为没有办法区分'no'那来自true与来自的那个false.


Playground 代码链接

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

为什么以“T extends undefined”为条件的 Typescript 类型(用“boolean”实例化 T)会将 T 解析为“never”? 的相关文章

  • 将实体投射到 dto

    只是想知道将 NestJS 实体对象转换为 DTO 的最佳方法 可以说我有以下内容 import IsString IsNumber IsBoolean from class validator import Exclude from cl
  • Kotlin JavaScript 到 TypeScript 定义文件

    我已经找到了ts2kt 库 https github com Kotlin ts2kt这将从任意位置创建 Kotlin 头文件 d ts文件 但是 我想朝相反的方向走 我想构建一个可以编译为 JavaScript 的 Kotlin 库 但我
  • 让Webpack不捆绑文件

    所以现在我正在使用一个原型 我们使用 webpack 用于构建 tsx 文件和复制 html 文件 和 webpack dev server 之间的组合来提供开发服务 正如您可以假设的那样 我们也使用 React 和 ReactDOM 作为
  • TypeScript:实现具有调用签名和索引签名的接口

    我想创建一个满足此类型的对象 interface I string x string number 并通过 TypeScript 类型检查 理想情况下 我希望不需要诉诸技巧 例如使用any作为中间步骤 我知道可以将其他字段添加到具有调用签名
  • 在严格模式下,一个对象字面量不能有多个同名属性

    这是我的代码 import combineReducers from redux import postReducers from postReducers import stationsReducer from TrackCircuitS
  • Angular2 authguards 执行异步函数失败

    我想通过检查用户是否从服务器登录来保护我的路由 但异步函数不会被执行 这是我的代码 canActivate route ActivatedRouteSnapshot state RouterStateSnapshot Observable
  • 如何使用 TS 配置 CRA 以支持 nullish-coalescing-operator

    所以我开始了一个新的 CRA 项目 我正在使用 TS beta 来获得一些不错的功能 例如链接运算符 但我也想使用nullish coalescing operator ifExists elseUseThis 不幸的是它不能开箱即用 并告
  • 如何从 Visual Studio Code API 打开浏览器

    我只是在探索一种从用于开发扩展的 Visual Studio Code API 打开默认浏览器的方法 以下是我的代码 var disposable vscode commands registerCommand extension brow
  • 多重混合助手会导致意外的不可分配编译器错误。我做错了吗?

    我正在尝试输入一个多混合辅助函数 该函数接受构造函数的映射并返回用一些新接口扩展的那些构造函数的映射 考虑以下设计的基类 class Alpha alpha string alpha class Beta beta string beta
  • 在 TypeScript 中推断函数参数

    我正在尝试创建一个类型安全的映射函数 不是下面的函数 但我坚持让函数参数正确推断 export type Mapper u mapped Mapped u export type Unmapped name string args any
  • 如何在 ngrx/effects 中执行 if/else 操作?

    我正在使用 ngrx effects 我想根据以下情况分派不同的操作foo商店里的状态 这就是我现在正在做的 Effect foo1 this updates whenAction Actions FOO filter obj gt obj
  • 在 TypeScript 中将 Chai 自定义插件声明为 NodeJS 全局变量

    这是我之前的问题 https stackoverflow com questions 61676032 declare nodejs global variables in before hook in webdriverio using
  • Angular2:鼠标事件处理(相对于当前位置的移动)

    我的用户应该能够通过鼠标在画布中移动 或旋转 对象 当鼠标事件发生时 屏幕坐标用于计算与最后一个事件的增量 方向和长度 没什么特别的 mousedown 获取第一个坐标 mousemove 获取第n个坐标 计算deltaXY 按deltaX
  • 如何避免 TypeScript 中出现虚假的“未使用参数”警告

    我遇到过很多次这种情况 最后决定弄清楚正确的方法是什么 如果我有一个声明方法的抽象父类 然后一些具体子类在其实现中实现真正的逻辑 并且显然使用方法参数 但某些子类不需要在该方法中执行任何操作 因此不要使用方法参数 那些不必执行任何操作的方法
  • 由于 CORS 错误,POST 请求在 React axios 中被阻止[重复]

    这个问题在这里已经有答案了 我正在尝试向包含多部分数据的 API 发送 POST 请求 我在 postman 中测试了 API 一切正常 但是当我在react中调用API时 它给了我CORS错误 我交叉检查了 URL 标头和数据 对我来说一
  • 在 TypeScript 中实现类型安全的服务注册表

    我想要一个函数根据给定的标识符 例如字符串或符号 返回对象实例 在代码中它可能看起来像这样 define your services type ServiceA foo gt string const ServiceA foo gt bar
  • Keycloak-js updateToken(minValidity) 需要澄清

    我在Keycloak js中阅读了很多该方法的示例 但没有对以下方法进行明确的解释 updateToken minValidity number KeycloakPromise
  • TypeScript 中的循环类型引用

    我是打字稿新手 正在尝试了解如何在两种类型之间设置循环引用 该参考不必是完整的代码参考 只需是接口 而是在单独的文件中定义接口 例如 假设我有两个接口 Parent 和 Child 它们是双向链接的 这样父级有子级的集合 并且每个子级都有对
  • TypeScript 支持互斥类型吗?

    我有一个带有参数的方法 我希望 TypeScript 验证传入的对象 在编译时 我知道运行时是一种不同的动物 仅满足允许的接口之一 Example interface Person ethnicity string interface Pe
  • Angular 6 中的 Http 错误处理

    我正在尝试使用 Angular 6 中的以下类来处理 http 错误 我从服务器收到 401 未经授权状态 但我没有看到控制台错误消息 HttpErrorsHandler ts 文件 import ErrorHandler Injectab

随机推荐