设置还原动作的关键点和反应还原动作 [英] keyof and React Redux action

查看:19
本文介绍了设置还原动作的关键点和反应还原动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Reaction Redux工具包和keyof来指定我的操作有效负载的一个元素应该是我的状态组成的类型的键,这样我就可以使用Redux操作更新状态的属性。 不管怎么说,它说的是: 类型字符串|数字不可分配给类型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;
    }
  }
});

推荐答案

这是打字稿突变的典型问题。 您可以在in my blog和其他SO答案中找到完整和详细的说明:[firstsecondthird]

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;
    }
  }
});

Playground

这篇关于设置还原动作的关键点和反应还原动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆