admin管理员组

文章数量:1429931

Using spread operator or Object.assign will lose strict typescript check.

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

I've try with Vanilla TS, still problem

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

It seems there are some bugs with ts. I want to know if there is a simple way to update the state with strict type checking? Could anyone guide me through this?

Using spread operator or Object.assign will lose strict typescript check.

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

I've try with Vanilla TS, still problem

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

It seems there are some bugs with ts. I want to know if there is a simple way to update the state with strict type checking? Could anyone guide me through this?

Share Improve this question edited Jul 5, 2019 at 9:38 minus.273 78713 silver badges26 bronze badges asked Jul 5, 2019 at 9:32 dabusidedabuside 1131 silver badge8 bronze badges 1
  • 3 Pedantry: ... isn't an operator (and can't be, it does things operators can't do). It's just syntax. – T.J. Crowder Commented Jul 5, 2019 at 9:35
Add a ment  | 

2 Answers 2

Reset to default 4

Yes, this seems to be a known issue from within the Typescript munity. Check this discussion on Github out

There is a workaround for this. Reference to it can be found here.

TLDR;

You basically type your new state before merging the two to form a new one. Two correctly typed states will result in a correctly typed state.


Take a look at this snippet:

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

From this, this is what I reckon your new code will look like:

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

iamfeek's answer (assign the new state to a variable/constant with the correct type in order to typecheck it, then merge in from that variable/constant) is correct as far as it goes, but you'll probably want to add Partial to your real use case.

setState(prevState => {
  const merge:Partial<State> = { key3: "" } }; // Flags up the error
  return { ...prevState, ...merge }; // Or return Object.assign({}, prevState, merge);
});

Partial<State> allows the merge object to only have a subset of State's properties, but doesn't let it have incorrect properties.

Perhaps even give yourself a utility function for it:

function mergeState(state:State, merge:Partial<State>) {
  return { ...prevState, ...merge };
}

then

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

本文标签: javascripttype check and spread operator (setState)Stack Overflow