【问题标题】:Why Typescript throw error message: Property does not exist on type?为什么 Typescript 会抛出错误消息:类型上不存在属性?
【发布时间】:2019-11-14 15:56:24
【问题描述】:

我创建了两个代码示例。它们之间的唯一区别是我传递给 switch 运算符的表达式。

在第一种情况下,我使用对象属性。而且效果很好。

在第二种情况下,我创建了一个 type 变量。并且 Typescript 会抛出错误消息:

“操作”类型上不存在属性“名称”。

类型 '{ type: "reset"; 上不存在属性 'name'; }'。

为什么会这样?

对象属性action.type和变量type属于同一类型'reset' | 'update'

interface State {
    name: string;
    cars: any[];
}

type Action = { type: 'reset' } | { type: 'update', name: string };

function reducer(state: State, action: Action): State {
    switch (action.type) {
        case 'update':
            return { ...state, name: action.name };
        case 'reset':
            return {...state, cars: [] };
        default:
            throw new Error();
    }
}

interface State {
    name: string;
    cars: any[];
}

type Action = { type: 'reset' } | { type: 'update', name: string };

function reducer(state: State, action: Action): State {
    /**
    * Create a 'type' variable
    */
    const { type } = action;

    switch (type) {
        case 'update':
            return { ...state, name: action.name };
    /**
    * Typescript will throw an error message
    * Property 'name' does not exist on type 'Action'.
    * Property 'name' does not exist on type '{ type: "reset"; }'.
    */
        case 'reset':
            return {...state, cars: [] };
        default:
            throw new Error();
    }
}

Image description

【问题讨论】:

  • type Action = { type: 'reset' } | { 类型:'更新',名称:字符串 };您必须在此处为 name 属性设置一个值,而不是 name: string.

标签: typescript redux


【解决方案1】:

基本上,Typescript 不会跟踪变量 actiontype 的类型之间的关系;当type 的类型被缩小时(例如在switch 语句的case 中),它也不会缩小action 的类型。

在赋值const { type } = action; 上,编译器推断type: Action['type'],恰好是'reset' | 'update'。后来,case 表达式并没有缩小action 的类型,因为没有对action 进行类型保护检查。

要让它按照您希望的方式运行,编译器必须引入类型变量T extends Action['type'] 并推断type: T,同时将action 缩小为: Action & { type: T } 类型。那么当type的类型变窄时,T本身就得变窄,所以效果会传播到action的类型,这会涉及到T

在每个变量赋值中引入一个像这样的新类型变量,并且控制流缩小类型变量的上限,会使类型检查算法大大复杂化。这也会使推断类型变得非常复杂,使用户更难理解;所以 Typescript 不这样做是合理的。一般来说,类型检查器并不能证明代码的所有可证明属性,这是一个示例。

【讨论】:

    【解决方案2】:

    当您引用参数时,它可以从整个对象推断类型,但是当您创建一个常量时,您将类型限制为简单地变为 "reset" | "update" 并且 Action 对象类型信息的其他位丢失。

    【讨论】:

      猜你喜欢
      • 2016-08-27
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      • 2020-06-27
      • 2016-01-04
      • 1970-01-01
      • 2019-04-12
      • 2020-07-09
      相关资源
      最近更新 更多