当我使用扩散运算符时,TypeScrip不能识别对象的属性是否针对空/未定义进行判断.

interface MyObject {
    date: SerializedDateTime;
    someId: number;
}

interface MyObjectInput {
    date?: Maybe<SerializedDateTime>;
    someId?: Maybe<number>;
}

function useMyObject(myObject: MyObject) {
    //Do something with myObject
}

function test(input: MyObjectInput) {

    if (!input.date) {
        throw new Error('Date not provided');
    }

    if (!input.someId) {
        throw new Error('SomeId not provided');
    }

    //This works...
    useMyObject({
        date: input.date,
        someId: input.someId,
    });

    //Here the compiler complains that the types are incompatible
    useMyObject({
        ...input
    });
}

确切的信息是:

Types of property 'date' are incompatible.    
Type 'Maybe<Date>' is not assignable to type 'Date'.       
Type 'undefined' is not assignable to type 'Date'

我不知道为什么会发生这种事.属性被判断为空/未定义,因此是兼容的,正如您可以看到的,当我不使用spad运算符时.有没有人知道这个问题的原因以及如何解决?

推荐答案

ms/TS#42384中出现了这个问题,其中属性的类型限制不会传播到父对象.该问题中描述的解决方法如下所示:

function assertField<T extends { [field in Field]?: T[field] }, Field extends keyof T & string,>(
  obj: T,
  field: Field
): obj is T & { [field in Field]: NonNullable<T[field]> } {
  if (!obj[field]) false;
  return true;
}
if (!assertField(input, "date")) throw new Error("Date not provided")

if (!assertField(input, "someId")) throw new Error("SomeId not provided")

useMyObject({
    ...input, // okay
});

其他一些解决方法包括assertion functions

function assertInput(input: MyObjectInput): asserts input is MyObject {
    if (!input.date) {
        throw new Error("Date not provided");
    }

    if (!input.someId) {
        throw new Error("SomeId not provided");
    }
}


function test(input: MyObjectInput) {
    assertInput(input);

    useMyObject({
        ...input, // okay
    });
}

type predicates (user-defined type guards).

function isGoodInput(input: MyObjectInput): input is MyObject {
    if (!input.date) {
        throw new Error("Date not provided");
    }

    if (!input.someId) {
        throw new Error("SomeId not provided");
    }

    return true
}

Playground (assertField)

Playground (assertion function)

Playground (type guard)

Typescript相关问答推荐

类型ElementTypes不可分配给类型ElementTypes.word'

如何在同一页面中使用布局和提供程序?

在OpenLayers 9.1中使用内置方法时,TypScript缩小联合类型

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

Angular 17 -如何在for循环内创建一些加载?

无法将select选项的值设置为ngFor循环中的第一个元素

如何为父类构造函数中的修饰属性赋值?

为什么TypeScript假设文档对象始终可用?

不推荐使用Marker类-Google map API警告

如何将CSV/TXT文件导入到服务中?

如何使默认导出与CommonJS兼容

在分配给类型的只读变量中维护const的类型

在HighChats列时间序列图中,十字准线未按预期工作

刷新页面时,TypeScrip Redux丢失状态

确保对象列表在编译时在类型脚本中具有唯一键

无法将从服务器接收的JSON对象转换为所需的类型,因此可以分析数据

API文件夹内的工作员getAuth()帮助器返回:{UserID:空}

如何将通用接口的键正确设置为接口的键

TypeScript:如何使用泛型和子类型创建泛型默认函数?

使用 fp-ts 时如何使用 TypeScript 序列化任务执行?