类型检查和传播运算符(setState)

时间:2019-07-05 09:32:43

标签: javascript reactjs typescript

使用传播运算符或Object.assign将失去严格的打字稿检查。

type State = {
  key1: string;
  key2: string;
};

function App() {
  const [state, setState] = React.useState<State>({
    key1: "",
    key2: ""
  });
  React.useEffect(() => {
    setState(prevState => {
      return { ...prevState, ...{ key3: "" } };//no ts error
    });
    setState(prevState => {
      return Object.assign({}, prevState, { key3: "" });//no ts error
    });
    setState({key1:'', key2:'', key3: ''});//ts error!!
  }, []);
  return <div>{JSON.stringify(state)}</div>;
}

我尝试使用Vanilla TS,还是有问题

type Person = {
    name: string,
    age: number
}
const person1:Person = {...{name: 'a', age: 20, salary: 20}};//no error
const person2:Person = Object.assign({name: 'a', age: 20, salary: 20});//no error
const person3:Person = {name: 'a', age: 20, salary: 20};//ts error

typescript playground link

似乎ts有一些错误。我想知道是否有一种使用严格类型检查来更新状态的简单方法?有人可以指导我做这个吗?

2 个答案:

答案 0 :(得分:3)

是的,这似乎是Typescript社区中的一个已知问题。 Check this discussion on Github out

有一个解决方法。 可以参考here

TLDR;

在合并两者以形成新状态之前,您基本上可以输入新状态。两种正确键入的状态将导致正确键入状态。


看看这个片段:

(() => {
    type State = { foo: string };
    const state: State = { foo: 'bar' };
    const assignedValues: State = { foo: 1 }; //complain expected
    const newState: State = Object.assign({}, state, assignedValues) 
})();

据此,我认为您的新代码将如下所示:

const [state, setState] = React.useState<State>({
    key1: "",
    key2: ""
  });
  React.useEffect(() => {
    setState(prevState => {
      const valueToChange: Partial<State> = { 
        key1: "I am sure that this is typed",
      }

      return Object.assign({}, prevState, valueToChange); 
    });
  }, []);
  return <div>{JSON.stringify(state)}</div>;

答案 1 :(得分:3)

iamfeek's answer(将新状态分配给具有正确类型的变量/常量以进行类型检查,然后从该变量/常量中合并)就目前而言是正确的,但是您可能会想要将setState(prevState => { const merge:Partial<State> = { key3: "" } }; // Flags up the error return { ...prevState, ...merge }; // Or return Object.assign({}, prevState, merge); }); 添加到您的实际用例中。

Partial<State>

State允许合并对象仅包含function mergeState(state:State, merge:Partial<State>) { return { ...prevState, ...merge }; } 的属性的子集,但没有使其具有不正确的属性。

也许甚至给自己一个实用程序功能:

setState(prevState => {
  return mergeState(prevState, { key3: "" } ); // Flags up the error
});

然后

{{1}}