dav*_*000 12 generics typescript redux
我有一个减速器,它有一个动作创建器,它可以是两种不同类型对象的数组,每个对象都有自己的接口。但是,我收到此错误
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'
Run Code Online (Sandbox Code Playgroud)
我怀疑这个错误是由于两个接口具有相似的值,除了 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;
};
Run Code Online (Sandbox Code Playgroud)
几件事:
第一的,
Array<A | B>
(A | B)[]
Run Code Online (Sandbox Code Playgroud)
都是相同的。
其次,之所以A可以分配给两者,是因为 A 的所有属性也在 B 中。
第三,不要改变状态。重新分配它还不够。
> const x = {}
undefined
> const y = x
undefined
> y.a = 1
1
> x
{ a: 1 }
Run Code Online (Sandbox Code Playgroud)
您可以 splat 进入一个新对象:let newState = { ...state }- 这通常就足够了。
好的。您不能将 type 的值分配A | B给 type 的值B。您使用了其他内容 ( type) 来表示不同的值,但 TS 无法知道这一点,除非您告诉它。您可以通过多种不同的方式来做到这一点。
首先,断言:
newState.b = action.data as B[];
Run Code Online (Sandbox Code Playgroud)
这实际上是在告诉 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;
}
Run Code Online (Sandbox Code Playgroud)
(注意:我实际上无法让它工作......代码是正确的,我只是never在第一次检查后获取操作类型 - 不确定这里发生了什么)
最后,让 TypeScript 通过 duck-typing 为您解决问题。
简而言之,如果对象中有一个与类型相关的属性,那么 TS 可以自动选择类型(如果该属性足够唯一)。
我怀疑这个错误是由于两个接口具有相似的值,除了 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;
Run Code Online (Sandbox Code Playgroud)
编辑:(我不能写评论)
@泰勒塞巴斯蒂安
Array<A | B>
(A | B)[]
Run Code Online (Sandbox Code Playgroud)
相同,但A[] | B[]不同
| 归档时间: |
|
| 查看次数: |
9919 次 |
| 最近记录: |