0

I have a State object that records time in days, hours, and minutes. I defined my state like this:

type StateKeys = "days" | "hours" | "minutes";

type State = {
    [K in StateKeys]: number
};

Later, I want to set state based on a value changed in a control. There are three controls, one for day, another for hours, and a third for minutes. I have one handler function that is hooked up to each of these controls. Here's an excerpt of that function:

_onTimeComponentChange(e: any) {
    const name : StateKeys = e.currentTarget.name;
    const updatedValue = parseInt(e.currentTarget.value);
    this.setState(
        //@ts-ignore
        {[name]: updatedValue}, 
        () => {
            this.updateValue();
        }
    )
}

My goal is to remove the //@tsignore comment. If I do that now, I get this error message:

Argument of type '{ [x: string]: number; }' is not assignable to parameter of type 'State | ((prevState: Readonly, props: Readonly) => State | Pick) | Pick'. Type '{ [x: string]: number; }' is missing the following properties from type 'Pick': days, hours, minutes

How do I remove the //@tsignorecomment and satisfy typescript's requirements?

2
  • 1
    Typescript does not do well with computed properties if the type computed property type is a union. I sometimes just pick one member and use a type assertion const name = e.currentTarget.name as "days"; looks dumb .. but it is what it is .. Commented Apr 1, 2019 at 23:43
  • Thanks @TitianCernicova-Dragomir. It definitely feels like black magic to me trying to satisfy Typescript. Commented Apr 2, 2019 at 16:57

1 Answer 1

4

It's definitely hard to get around this type of thing without casting. You can try following the pattern described here:

updateState(key: StateKeys, value: string) {
  this.setState((prevState) => ({
    ...prevState,
    [key]: value,
  }));
}

which would look like:

_onTimeComponentChange(e: any) {
  const name: StateKeys  = e.currentTarget.name
  const updatedValue = parseInt(e.currentTarget.value)
  this.setState(
    prevState => ({
      ...prevState,
      [name]: updatedValue,
    }),
    () => {
    },
  )
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.