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?
CodePudding user response:
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>;