我有一个reducer,它具有一个动作创建者,该动作创建者可以是两个不同类型的对象的数组,每个对象都有自己的接口。但是,我收到此错误
Type '(A | B)[]' is not assignable to type 'B[]'.
Type 'A | B' is not assignable to type 'B'.
Property 'productionId' is missing in type 'A' but required in type 'B'
我怀疑此错误是由于两个接口具有相似的值,除了B比A具有一个额外的值?
这是完整的可复制代码
interface A {
id: number;
name: string;
}
interface B {
id: number;
productionId: number;
name: string;
}
interface IAction<Data> {
type: string;
data: Data;
}
interface ISelectionOptionsReducerState {
a: A[];
b: B[];
}
let initialState: ISelectionOptionsReducerState = {
a: [],
b: []
};
type TAction = IAction<Array<A | B>>;
type TAction = IAction<A[] | B[]>; <= this didn't work either
type TReducer = (
state: ISelectionOptionsReducerState,
action: TAction
) => ISelectionOptionsReducerState;
const selectionOptionsReducer: TReducer = (
state: ISelectionOptionsReducerState = initialState,
action: TAction
): ISelectionOptionsReducerState => {
Object.freeze(state);
let newState: ISelectionOptionsReducerState = state;
switch (action.type) {
case '1':
newState.a = action.data;
break;
case '2':
newState.b = action.data; <= error happen here
break;
default:
return state;
}
return newState;
};
答案 0 :(得分:2)
我怀疑此错误是由于两个接口的值相似, 除了B比A具有额外的价值?
是的,您可以将B分配给A,但不能将A分配给B。
您需要输入保护:
function isA(data: A | B): data is A {
return typeof (data as B).productionId === 'undefined'
}
function isB(data: A | B): data is B {
return typeof (data as B).productionId === 'string'
}
...
case '1':
newState.a = action.data.filter(isA);
break;
case '2':
newState.b = action.data.filter(isB);
break;
编辑: (我不能写评论)
@泰勒·塞巴斯蒂安
Array<A | B>
(A | B)[]
相同,但A[] | B[]
不同
答案 1 :(得分:1)
耦合事物:
首先
Array<A | B>
(A | B)[]
都一样。
第二,A
可以同时分配给这两个原因是因为A的所有属性也都在B中。
第三,不要改变状态。重新分配是不够的。
> const x = {}
undefined
> const y = x
undefined
> y.a = 1
1
> x
{ a: 1 }
您可以使用新对象let newState = { ...state }
-通常就足够了。
好的。您无法将A | B
类型的值分配给B
类型的值。您已经使用其他(type
)来表示其他值,但是TS除非知道,否则不会知道。您可以通过多种不同的方式来做到这一点。
首先,断言:
newState.b = action.data as B[];
这实际上是在告诉TS窃听。通常,这很好。如果您做的事情确实值得怀疑,TS会让您先声明unknown
。不过,事实并非如此。
但是有更好的方法。
稍好一点:类型卫兵
这需要重构开关:
function isA(x: any): x is IAction<Array<A>> {
return x.type === '1'
}
function isB(x: any): x is IAction<Array<B>> {
return x.type === '2'
}
...
if (isA(action)) {
newState.a = action.data;
} else if (isB(action)) {
newState.b = action.data;
}
(注意:我实际上无法使它正常工作……代码正确,我只是在第一次检查后就输入never
进行操作-不确定这是怎么回事)
最后,let TypeScript do the resolution for you via duck-typing。
其中的tl; dr是,如果在对象中具有与类型相关联的属性,则如果该属性足够唯一,则TS可以自动选择类型。