我使用React Redux工具包和keyof来指定我的操作负载的一个元素应该是我的状态组成的类型的键,所以我可以使用redux操作来更新状态的属性。不管怎么说,它说: Type string | number是不可赋值给类型never的。在这一行中:
state[id][key] = value;你能给我解释一下这里的问题是什么吗?非常感谢!
interface MyType {
a: number;
b: string;
c: number;
};
const makeMyType = () => {
return {
a: 1,
b: 'b',
c: 2
} as MyType;
}
interface UpdateType<Type> {
id: number;
key: keyof Type;
value: Type[keyof Type];
}
const test_slice = createSlice({
name: 'test_slice',
initialState: [makeMyType(), makeMyType()];
reducers: {
updateProperty(state: MyType[], action: PayloadAction<UpdateType<MyType>) {
const {id, key, value} = action.payload;
state[id][key] = value;
}
}
});发布于 2021-07-29 14:51:35
这是typescript中突变的经典问题。您可以找到此in my blog的完整和详细解释,以及其他SO答案:[ first,second,third ]
TL;DR
和
对象的键类型是逆变的
因此,state[id][key]会产生以下错误:
Type 'string | number' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'这是因为string & number = never。请看第一句话:.... contra-variant positions causes an intersection。
TypeScript对state[id][key] = value并不确定。
此类型:
interface UpdateType<Type> {
id: number;
key: keyof Type;
value: Type[keyof Type];
}是弱的,并且允许表示非法状态。考虑下一个示例:
const x: UpdateType<MyType> = {
id: 2,
key: 'a',
value: 's' //<--- should be number
}如果你想让它更安全,你应该使用所有允许/合法状态的联合:
type Values<T> = T[keyof T]
/**
* Is a union of all valid states
*/
type UpdateType<Type> = Values<{
[Key in keyof Type]: {
id: number;
key: Key;
value: Type[Key];
}
}>但这并没有帮助我们解决这个问题。
如果你想修复它,你应该更上一层楼,只对state[id]进行变异。该值具有MyType类型。
有一件重要的事情我们应该知道- TS不跟踪突变。我们如何从中受益?
考虑这个例子:
const mutableUpdate = <
State extends MyType,
Key extends keyof State,
Value extends State[Key]
>(state: State, key: Key, value: Value) => {
state[key] = value;
return state
}上面的函数将帮助我们改变状态。完整示例:
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
interface MyType {
a: number;
b: string;
c: number;
};
const makeMyType = (): MyType => ({
a: 1,
b: 'b',
c: 2
})
type Values<T> = T[keyof T]
/**
* Is a union of all valid states
*/
type UpdateType<Type> = Values<{
[Key in keyof Type]: {
id: number;
key: Key;
value: Type[Key];
}
}>
const mutableUpdate = <
State extends MyType,
Key extends keyof State,
Value extends State[Key]
>(state: State, key: Key, value: Value) => {
state[key] = value;
return state
}
const test_slice = createSlice({
name: 'test_slice',
initialState: [makeMyType(), makeMyType()],
reducers: {
updateProperty(state: MyType[], action: PayloadAction<UpdateType<MyType>>) {
const { id, key, value } = action.payload;
const result = mutableUpdate(state[id], key, value);
state[id] = result;
}
}
});https://stackoverflow.com/questions/68576735
复制相似问题