[英]TypeScript mapped types inference not working as expected
Given this function: 给定此功能:
export const combineValidators = <Input extends { [P in keyof Input]: (val: string) => Err }, Err>(
validators: Input
) => (values: { [P in keyof Input]?: unknown }): { [P in keyof Input]: Err } => {
// Ignore implementation.
return {} as { [P in keyof Input]: Err };
};
And this usage: 和这种用法:
const validator = combineValidators({
name: (val) => val ? undefined : 'error',
email: (val) => val ? undefined : 'error'
});
const errors = validator({
name: 'Lewis',
email: 'lewis@mercedes.com'
});
I would expect TypeScript to be able to infer the return type as: 我希望TypeScript能够将返回类型推断为:
// Expected: `errors` to be inferred as:
interface Ret {
name: string | undefined;
email: string | undefined;
}
However it's inferred as: 但是可以推断为:
// Actual: `errors` inferred as:
interface Ret {
name: {};
email: {};
}
I've created a live example in the TypeScript playground demonstrating the issue. 我已经在TypeScript运动场中创建了一个实时示例来演示该问题。
Can anybody help? 有人可以帮忙吗?
Err
will not be inferred in the way you expect it. 不会以您期望的方式推断出Err
。 It might be simpler to use the ReturnType
conditional type to extract the return types from Input
: 使用ReturnType
条件类型从Input
提取返回类型可能更简单:
type ReturnTypes<T extends Record<keyof T, (...a: any[]) => any>> = {
[P in keyof T]: ReturnType<T[P]>
}
export const combineValidators = <Input extends Record<keyof Input, (val: unknown) => any>>(
validators: Input
) => (values: Record<keyof Input, unknown>): ReturnTypes<Input> => {
return {} as ReturnTypes<Input>;
};
const validator = combineValidators({
name: (val) => val ? undefined : 'error',
email: (val) => val ? undefined : 'error'
});
const errors = validator({
name: 'Lewis',
email: 'lewis@mercedes.com'
});
We can even go a bit further and if you specify parameters types in the validator function, you can get type checking for the fields of the object passed to validator
: 我们甚至可以更进一步,如果您在验证器函数中指定参数类型,则可以对传递给validator
的对象的字段进行类型检查:
type ParamTypes<T extends Record<keyof T, (a: any) => any>> = {
[P in keyof T]: Parameters<T[P]>[0]
}
type ReturnTypes<T extends Record<keyof T, (...a: any[]) => any>> = {
[P in keyof T]: ReturnType<T[P]>
}
export const combineValidators = <Input extends Record<keyof Input, (val: unknown) => any>>(
validators: Input
) => (values: ParamTypes<Input>): ReturnTypes<Input> => {
return {} as ReturnTypes<Input>;
};
const validator = combineValidators({
name: (val: string) => val ? undefined : 'error',
email: (val) => val ? undefined : 'error', // if we leave it out, we still get unknown
age: (val: number) => val ? undefined : 'error'
});
const errors = validator({
name: 'Lewis',
email: 'lewis@mercedes.com',
age: 0
});
const errors2 = validator({
name: 'Lewis',
email: 'lewis@mercedes.com',
age: "0" // type error
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.