0

This code fails to compile:

type Validator<T> = (value: string) => { value: T }

const createValidator = <TState extends any>(state: TState) =>
    <TName extends keyof TState>(x: TName, validator: Validator<TState[TName]>) => {
        return (value: { [P in TName]: string }): { [P in TName]: TState[TName] } => {
            const result = validator(value[x]);

            return { [x]: result.value };
        };
    }

return { [x]: result.value }; gives me Type '{ [x: string]: TState[TName]; }' is not assignable to type '{ [P in TName]: TState[TName]; }'. even though TName is inferred from x.

Why is that? And what can I do about it - except from casting the returned value?

6
  • Could you add Validator type to complete the picture, please? Commented Jan 19, 2023 at 18:18
  • @yevt sure, yes, sorry. It's edited in now. Commented Jan 19, 2023 at 18:35
  • Please edit the code to be a self-contained minimal reproducible example that demonstrates your issue when pasted as-is into a standalone IDE and does not have unrelated errors. Right now Validator depends on other things we don't have access to. You might want to clear that up either by defining those (and making sure that they doesn't point to further third-party types we don't have) or, even better, by replacing them with built-in types. Commented Jan 19, 2023 at 18:50
  • @jcalz yes, sorry about that. This was too hurried, I agree. Commented Jan 19, 2023 at 19:37
  • For sure @jcalz knows more about the key type narrowing in object literals and could correct my answer. Commented Jan 19, 2023 at 19:58

1 Answer 1

1

The problem here is, that TypeScript doesn't infer index signatures in object literals with computed properties. The most minimal example:

type KEY = 'foo' | 'bar';
let obj = { ['foo' as KEY]: 1 };

// obj is of type: { [x: string ]: number }
// and NOT the { foo: number, bar: number }
// and NOT the Record<'foo'|'bar', number>

So in your example you should cast, and to make it simpler, reuse types from variables to not repeat yourself:

return { [x]: result.value } as Record<typeof x, typeof result.value>;
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Do you know if there are any open issues regarding such feature?
FYI, this is microsoft/TypeScript#13948 and I usually keep around a kv() function as shown here to work around it.

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.