简体   繁体   English

TypeScript映射类型推断无法按预期工作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM