本文介绍了为什么打字稿会抛出错误消息:类型上不存在属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created two code examples. The only difference between them is what expression I pass to the switch operator.

在第一种情况下,我使用对象属性.它工作正常.

In a first case I use an object property. And it works fine.

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

In a second case I create a type variable. And Typescript throw an error message:

操作"类型上不存在属性名称".

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

Property 'name' does not exist on type '{ type: "reset"; }'.

为什么会这样?

对象属性action.type 和变量type 的类型相同'reset' |'更新'.

The object property action.type and variable type are of the same 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();
    }
}

图片说明

推荐答案

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

Basically, Typescript doesn't keep track of a relationship between the types of the variables action and type; when type's type is narrowed (such as in a case of a switch statement), it doesn't also narrow action's type.

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

On the assignment const { type } = action;, the compiler infers type: Action['type'], which happens to be 'reset' | 'update'. Later, the case expression doesn't narrow the type of action because no type-guarding check was done on action.

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

For this to behave the way you want it to behave, the compiler would have to introduce a type variable T extends Action['type'] and infer type: T, while simultaneously narrowing action to the type : Action & { type: T }. Then when type's type is narrowed, T itself would have to be narrowed, so the effect would propagate to action's type which would involve T.

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

Introducing a new type variable like this on every variable assignment, and control-flow narrowing the upper bounds of type variables, would greatly complicate the type-checking algorithm. It would also greatly complicate the inferred types making them harder for users to understand; so it's reasonable that Typescript doesn't do this. Generally speaking, type-checkers don't prove every provable property of your code, and this is an example.

这篇关于为什么打字稿会抛出错误消息:类型上不存在属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 05:51