我需要根据特定属性值的undefined状态过滤array.为了实现这一点,我使用了一个类型谓词来强制filter结果的类型.数组中的值包含一个必需属性,该属性在类型谓词的类型中是可选的.

使用以下示例(TS Playground):

interface OptionalModel {
  prop?: string;
  otherProp: number;
}

interface RequiredModel {
  prop: string | undefined;
  otherProp: number | undefined;
}

const array: RequiredModel[] = [];

// How to filter/convert `array` to an array of `OptionalModel` ?

const filterKO = array.filter((value): value is OptionalModel => typeof value.otherProp !== 'undefined'); // ✗

filterKO的声明中有一个错误.TS在类型谓词中表示OptionalModel:

A type predicate's type must be assignable to its parameter's type.
  Type 'OptionalModel' is not assignable to type 'RequiredModel'.
    Property 'prop' is optional in type 'OptionalModel' but required in type 'RequiredModel'.(2677)

由于OptionalModel中的可选属性,不可能使用类型谓词;但是,由于RequiredModel中可能有undefined个其他属性,因此不可能将array直接用作OptionalModel[].

我怎么才能实现过滤,把filterKO种缩小到OptionalModel[]种呢?

推荐答案

TypeScrip大多不会对任意类型的Mutations 进行建模.该语言不想让您接受V类型的值v,对于任意VW,它的类型W只接受change.

相反,它模拟了两个基本的类型变化.第一个是widening,这(第一个近似值)是安全的.如果每个V类型的值也是W类型的值,则可以安全地将V赋给需要W的位置.为此,您不需要类型谓词或任何其他内容;只需将其赋给具有更宽类型的新变量annotated:

第二种是narrowing,一般不安全.如果类型W的每个值也是类型V的值,但如果不是类型V的每个值也是类型W的值,那么你不能在应该是W的地方分配V. 相反,为了安全起见,您应该在V上执行某种type guarding,以确保它也是W. TypeScript有很多工具可以做到这一点,包括type predicates,它可以让你编写自定义类型保护函数.


但你不能通过扩大或缩小直接从RequiredModelOptionalModel.RequiredModelOptionalModel都不能分配给另一个.因此,你不能立即使用扩大或缩小两种方法.

不过,这并不是不可能的.即使VW都不是另一个的子类型,您也可以引入第三个类型并将其用作中介.例如,union type V | WVW的加宽.类型V的每个值都可以赋给类型V | W.并且类型W的每个值也可分配给类型V | W.因此,您可以自由地从V加宽到V | W,然后使用缩小技术将其从V | W缩小到W.


这看起来是这样的:

const array: RequiredModel[] = [];

const widenedArray:
  (RequiredModel | OptionalModel)[] = array; // okay

const filtered = widenedArray.filter(
  (value): value is OptionalModel => typeof value.otherProp !== 'undefined'
);
// const filtered: OptionalModel[] // okay

首先,我们将arrayRequiredModel[]扩展到(RequiredModel | OptionalModel)[],将其引用复制到widenedArray. 然后,我们通过类型谓词回调将widenedArray(RequiredModel | OptionalModel)[]缩小到OptionalModel[].

Playground link to code

Typescript相关问答推荐

如何在类型脚本中声明对象其键名称不同但类型相同?

VS代码1.88.0中未出现自动导入建议

TypeScript实用程序类型—至少需要一个属性的接口,某些指定属性除外

contextPaneTitleText类型的参数不能分配给remoteconfig类型的关键参数'""'''

根据另一个属性的值来推断属性的类型

TypeScrip-将<;A、B、C和>之一转换为联合A|B|C

通过字符串索引访问对象';S的值时出现文字脚本错误

在Reaction-Native-ReAnimated中不存在Animated.Value

使用Redux Saga操作通道对操作进行排序不起作用

具有自引用属性的接口

`fetcher.load`是否等同于Get Submit?

常量类型参数回退类型

避免混淆两种不同的ID类型

对有效枚举值的常量字符串进行常规判断

如何为带有参数的函数类型指定类型保护?

类型';只读<;部分<;字符串|记录<;字符串、字符串|未定义&>';上不存在TS 2339错误属性.属性&q;x&q;不存在字符串

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

如何知道使用TypeScript时是否在临时工作流内运行

如何通过nx找到所有受影响的项目?

使用 TypeScript 在 SolidJS 中绘制 D3 力图