简体   繁体   English

为什么 Typescript 会抛出错误信息:类型上不存在属性?

[英]Why Typescript throw error message: Property does not exist on type?

I created two code examples.我创建了两个代码示例。 The only difference between them is what expression I pass to the switch operator.它们之间的唯一区别是我传递给 switch 运算符的表达式。

In a first case I use an object property.在第一种情况下,我使用 object 属性。 And it works fine.它工作正常。

In a second case I create a type variable.在第二种情况下,我创建了一个type变量。 And Typescript throw an error message:并且 Typescript 抛出错误信息:

Property 'name' does not exist on type 'Action'. “操作”类型上不存在属性“名称”。

Property 'name' does not exist on type '{ type: "reset";类型 '{ type: "reset"; 上不存在属性 'name' }'. }'。

Why is this happening?为什么会这样?

The object property action.type and variable type are of the same type 'reset' | 'update' object 属性action.type和变量type属于同一类型'reset' | 'update' 'reset' | 'update' . '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图片说明

Basically, Typescript doesn't keep track of a relationship between the types of the variables action and type ;基本上, Typescript 不会跟踪变量actiontype的类型之间的关系; when type 's type is narrowed (such as in a case of a switch statement), it doesn't also narrow action 's type.type的类型被缩小时(例如在switch语句的case ),它也不会缩小action的类型。

On the assignment const { type } = action;关于赋值const { type } = action; , the compiler infers type: Action['type'] , which happens to be 'reset' | 'update' ,编译器推断type: Action['type'] ,恰好是'reset' | 'update' 'reset' | 'update' . 'reset' | 'update' Later, the case expression doesn't narrow the type of action because no type-guarding check was done on action .后来, case表达式并没有缩小action的类型,因为没有对action进行类型保护检查。

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 } .为了让它按照你希望的方式运行,编译器必须引入一个类型变量T extends Action['type']并推断type: T ,同时将action缩小到 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 .然后当type的类型变窄时, T本身也必须变窄,因此效果会传播到涉及Taction的类型。

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.所以 Typescript 不这样做是合理的。 Generally speaking, type-checkers don't prove every provable property of your code, and this is an example.一般来说,类型检查器并不能证明代码的所有可证明属性,这是一个示例。

When you refer to the argument it can infer the type from the whole object but when you create a constant you limit the type to simply become "reset" | "update"当您引用参数时,它可以从整个 object 中推断出类型,但是当您创建一个常量时,您将类型限制为简单地变为"reset" | "update" "reset" | "update" and the other bits of Action object type info is lost. "reset" | "update"和 Action object 类型信息的其他位丢失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM