用于提取函数参数类型的条件类型

时间:2018-07-15 16:49:47

标签: typescript conditional-types

我有此泛型类型,可用于提取函数的第二个参数的类型:

type SecondParam<T> = T extends (a: any, b: infer R) => any
  ? R
  : never;

它适用于大多数情况:

type T1 = SecondParam<(x: any, y: number) => void>; // number
type T2 = SecondParam<(x: any, y: { x: string[] }) => void>; // { x: string[] }

但是当第二个参数不存在时,我希望它给我void而不是{}

type T3 = SecondParam<(x:any) => any> // is {}, I want void

我正在使用SecondParam定义另一个函数的类型:

type F<T> = (p: SecondParam<T>) => void;
type F1 = F<(x: any, y: number) => any>; // (p: number) => void
type F2 = F<(x: any, y: { x: string[] }) => any>; // (p: { x: string[] }) => void
type F3 = F<(x: any) => any>; // is (p: {}}) => void, but I want () => void

但是在缺少第二个参数的情况下,对于最后一种情况效果不佳。

1 个答案:

答案 0 :(得分:2)

类型confition (a: any, b: infer R) => any ? .. : ..始终为true,因为省略参数不会产生编译错误,请参见以下示例进行编译:

const abc: (one: string, two: string, three: string) => void = (onlyFirst: string) => { };

如果您确实希望将() => void作为类型,则必须在SecondParam类型上添加一个新的类型条件。像这样:

type SecondParam<T> = T extends (a: any, b: infer R) => any
  ? R
  : never;

type F<T> = T extends (a: any) => any
  ? () => void
  : (p: SecondParam<T>) => void;

type F3 = F<(x: any) => any>; // is () => void

如果您想输入never,而您实际上无法分配它,则可以像这样更改SecondParam类型

type SecondParam<T> = T extends (a: any) => any
  ? never
  : T extends (a: any, b: infer R) => any
    ? R
    : never;

// you now, can't pass the second parameter as its never:
const f: F3 = () => { };
f(); // expects 1 argument