0

My code:

const state = { activeRequests: 0, test: true };
type state = typeof state;
type pState = Partial<state>;
type stateKeys = keyof state; // "activeRequests" | "test"
...
set: (state: state, p: pState) => Object.keys(p).forEach(k => (state[k] = p[k]))

Error at state[k] = p[k]:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ activeRequests: number; test: boolean; }'.
No index signature with a parameter of type 'string' was found on type '{ activeRequests: number; test: boolean; }'

Looks like k has string type. There are some of my attempts:

Object.keys(p).forEach((k: stateKeys) => state[k].push(p[k]))
Error: Type 'string' is not assignable to type '"activeRequests" | "test"'`.
Object.keys(p).forEach(k => (state[k as stateKeys] = p[k])
Error: Type 'any' is not assignable to type 'never'`
(Object.keys(p) as stateKeys[]).forEach(k => (state[k] = p[k]))
Error: Type 'number | boolean | undefined' is not assignable to type 'never'.
  Type 'undefined' is not assignable to type 'never'.

What is wrong?

2 Answers 2

1

You can't do that cleanly without generics. Plus you are trying to assign a partially undefined value to a type that doesn't allow undefined. So you need to handle that scenario. Here's a potential solution:

var t = function<TState>(state: TState, p: Partial<TState>) {
    let keys = Object.keys(p) as (keyof TState)[];
    for (let key of keys) {
        state[key] = p[key] ?? state[key];
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

because you are trying to assing object like this:

{
  activeRequests: number | boolean | undefined, 
  test: number | boolean | undefined
}

to:

{
  activeRequests: number, 
  test: boolean,
}

because of the partial and stateKeys part.

Solution is simple like that:

const set = (state: state, p: pState) => ({...state, ...p})

3 Comments

I added solution to main answer
Thank you for your example of solution, but this will create new object. I'd really like to mutate existing state. Is there no way to make this work my way?
You would need to add if statement working as type guards for typescript: const set = (state: state, p: pState): void => { Object.keys(p).forEach(k => { if (k === 'activeRequests') { const a = p[k]; if (a) { state[k] = a; } } }) }

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.