typescript - 为什么 Typescript 会抛出错误消息:类型上不存在属性?
问题描述
我创建了两个代码示例。它们之间的唯一区别是我传递给 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();
}
}
解决方案
基本上,Typescript 不会跟踪变量类型action
和type
;之间的关系。当type
's 类型被缩小时(例如在 a case
ofswitch
语句中),它也不会缩小action
's 类型。
在赋值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 不这样做是合理的。一般来说,类型检查器并不能证明代码的所有可证明属性,这是一个示例。
推荐阅读
- jquery - 如何更改全日历中的背景颜色
- powershell - 查找不是特定 GG 组成员的用户?
- c++ - C++ 中的二维数组 -
- java - 如何在文件中写入 JSON 对象
- mysql - How to user ALTER statement with GENERATE ALWAYS INSIDE mysql function?
- ios - Why does APNS deliver only last queued notification instead of all queued notifications?
- javascript - Using CSS selector in DTM to create an event based rule
- android - Android 图标在预览中未正确显示
- php - Not going into if statement when pressing a button
- javascript - Klarna Payment gateway integration with WebFlow project