我有一些类似的功能:
actions.ts
export const addToCart = (id: string) => ({
id,
type: 'ADD_TO_CART',
});
export const emptyCart = () => ({
type: 'EMPTY_CART',
});
export const removeFromCart = (id: string) => ({
id,
type: 'REMOVE_FROM_CART',
});
export type Action =
| ReturnType<typeof addToCart>
| ReturnType<typeof emptyCart>
| ReturnType<typeof removeFromCart>;
reducer.ts
import { Action } from './actions';
import { State } from './state';
export default (state: State, action: Action): State => {
switch (action.type) {
case 'ADD_TO_CART': {
return [...state, action.id];
}
case 'EMPTY_CART': {
return [];
}
case 'REMOVE_FROM_CART': {
return state.filter(id => id !== action.id);
}
default:
return state;
}
};
我的IDE告诉我类型Action
是:
type Action = {
id: string;
type: string;
} | {
type: string;
} | {
id: string;
type: string;
}
但是,action.id
中reducer.ts
的两种情况都引发此Typescript错误:
Property 'id' does not exist on type 'Action'.
Property 'id' does not exist on type '{ type: string; }'.
这是什么问题?我的类型似乎正确,并且我使用的是其中一个类型选项中存在的对象键之一。
答案 0 :(得分:4)
您已经创建了一个潜在的discriminated union type Action
,但是您的判别式属性type
扩展为string
类型-这就是TS无法查明的原因,你的意思是工会的一部分。
一个简单的解决方法是使用as const
注释动作创建者函数的返回类型,因此保留字符串type
的文字类型:
export const addToCart = (id: string) => ({
id,
type: 'ADD_TO_CART',
}) as const; // add `as const`
// do this for the other functions as well
答案 1 :(得分:0)
对福特出色答案的补充
从对问题的评论中:
只是看了看您的链接,我不确定示例在做什么,我的代码没有做
您的问题是,您在欺骗联合中的类型:您期望推理引擎过多。您需要使用type
或interface
而不是(ab)使用ReturnType
来明确地键入化简动作,一切都会好起来的。:
type AddToCart = {
type: 'ADD_TO_CART',
id: string,
};
type EmptyCart = {
type: 'EMPTY_CART'
};
type ReducerAction = AddToCart | EmptyCart;
const reducer = (state: any, action: ReducerAction) => {
switch (action.type) {
case 'ADD_TO_CART': console.log(action.id); // ok!
case 'EMPTY_CART': console.log(action.id); // compiler error!
}
}