问题描述
我创建了两个代码示例.它们之间的唯一区别是我传递给 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 不会跟踪变量 action
和 type
的类型之间的关系>;当 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.
这篇关于为什么打字稿会抛出错误消息:类型上不存在属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!