首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >keyof和React Redux操作

keyof和React Redux操作
EN

Stack Overflow用户
提问于 2021-07-29 13:22:47
回答 1查看 162关注 0票数 0

我使用React Redux工具包和keyof来指定我的操作负载的一个元素应该是我的状态组成的类型的键,所以我可以使用redux操作来更新状态的属性。不管怎么说,它说: Type string | number是不可赋值给类型never的。在这一行中:

代码语言:javascript
复制
state[id][key] = value;

你能给我解释一下这里的问题是什么吗?非常感谢!

代码语言:javascript
复制
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;
    }
  }
});
EN

回答 1

Stack Overflow用户

发布于 2021-07-29 14:51:35

这是typescript中突变的经典问题。您可以找到此in my blog的完整和详细解释,以及其他SO答案:[ firstsecondthird ]

TL;DR

对象的键类型是逆变的

因此,state[id][key]会产生以下错误:

代码语言:javascript
复制
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并不确定。

此类型:

代码语言:javascript
复制
interface UpdateType<Type> {
  id: number;
  key: keyof Type;
  value: Type[keyof Type];
}

是弱的,并且允许表示非法状态。考虑下一个示例:

代码语言:javascript
复制
const x: UpdateType<MyType> = {
  id: 2,
  key: 'a',
  value: 's' //<--- should be number
}

如果你想让它更安全,你应该使用所有允许/合法状态的联合:

代码语言:javascript
复制
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不跟踪突变。我们如何从中受益?

考虑这个例子:

代码语言:javascript
复制
const mutableUpdate = <
  State extends MyType,
  Key extends keyof State,
  Value extends State[Key]
>(state: State, key: Key, value: Value) => {
  state[key] = value;
  return state
}

上面的函数将帮助我们改变状态。完整示例:

代码语言:javascript
复制
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;
    }
  }
});

Playground

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68576735

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档