我感兴趣的是构建这样的类型谓词函数,当数字是实数时,它将返回true,同时使类型更严格:

function isRealNumber(input: number | undefined | null): input is number {
    return input !== undefined && input !== null && Number.isFinite(input);
}

然而,在某些情况下,当取反时,这会产生不正确的类型,例如:

const myNumber: number | null = NaN as any;
if (isRealNumber(myNumber)) {
    const b = myNumber;  // b is number, correct
} else {
    const b = myNumber;  // b is `null`, should be `null | number`
}

这可以在条件中使用多个语句来解决,但这并不理想:

function isRealNumber(input: number | undefined | null): boolean {
    return input !== undefined && input !== null && Number.isFinite(input);
}

const myNumber: number | null = NaN as any;
if (isRealNumber(myNumber) && myNumber !== null && myNumber !== undefined) {
    const b = myNumber;  // b is number, correct
} else {
    const b = myNumber;  // b is `null | number`, correct
}

typescript中是否有任何方法可以使用单个函数来正确地缩小类型范围,而有时在求反时也不会生成错误的类型?

推荐答案

您正在寻找microsoft/TypeScript#15048中要求的"单面"或"细粒度"type predicate,但目前TypeScript中不直接支持这一点.这个问题是公开的,但不清楚这里会发生什么.

不过,在这个问题上有一个解决方案mentioned.如果您将保护类型从input is number更改为input is RealNumber,其中RealNumber是可分配给但严格小于number的类型,那么事情就会开始工作.

虽然RealNumbernumber之间在类型系统中没有实际的区别,但你可以使用一种称为branded primitives的技术来"伪造"一个.在这里,我们使用numberintersect等基本类型,其中对象类型包含幻像"brand"或"tag"属性.例如:

function isRealNumber(input: number | undefined | null): input is number & { __realNumber?: true } {
    return input !== undefined && input !== null && Number.isFinite(input);
}

const myNumber: number | null = NaN as any;
if (isRealNumber(myNumber)) {
    const b = myNumber;  // b is number & {__realNumber?: true}
} else {
    const b = myNumber;  // b is number | null
}

这看起来更合理.如果isRealNumber(myNumber)true,则b缩小为number & {__realNumber?: true}.{__realNumber?: true}属性在运行时实际上并不存在(它是一个"幻影"属性),但这应该无关紧要,因为b仍然是number.当isRealNumber(myNumber)false时,那么b根本就不窄.

Playground link to code

Typescript相关问答推荐

相交TypScript中的对象和接口

使用新控制流的FormArray内部的Angular FormGroup

Tailwind CSS样式不在Svelte应用程序中呈现

使用前的组件渲染状态更新

如何使类型只能有来自另一个类型的键,但键可以有一个新值,新键应该抛出一个错误

使用带有RxJS主题的服务在Angular中的组件之间传递数据

如何判断输入是否是TypeScript中的品牌类型?

如何使用泛型自动推断TS中的类型

使用打字Angular 中的通用数据创建状态管理

表单嵌套太深

如何使用模板继承从子组件填充基础组件的画布

ANGLE NumberValueAccessor表单控件值更改订阅两次

类型脚本-处理值或返回值的函数

在打字脚本中对可迭代对象进行可变压缩

是否可以通过映射类型将函数参数约束为预定义类型?

在抽象类属性定义中扩展泛型类型

打印脚本中正则函数和函数表达式的不同类型缩小行为

如何在Nextjs路由处理程序中指定响应正文的类型

如何限定索引值必须与相应属性的id字段相同

元组解释