修剪/映射特定函数和类型T的并集,以及将独立T映射到函数

时间:2018-10-09 14:27:20

标签: typescript typescript2.0 conditional-types

抱歉,标题复杂,我想不出更好的标题。

其他背景:这需要在TS 2.8.4上工作

我需要一些有关映射类型的帮助

// Input types:
type FunctionOrObject<Arg, Result> =
| ((arg: Arg) => Partial<Result>)
| Partial<Result>;

interface ExampleArg {
  disabled: boolean;
}
interface ExampleResult {
  root: string;
  sub: string;
}

type FuncOrObj = FunctionOrObject<ExampleArg, ExampleResult>;
type Standalone = ExampleResult;

// Expected should have the type (arg: Arg) => Partial<Result>
type Expected = MagicMappingType<FuncOrObj >;

//  Expected2 should have the type (...args: any[]) => Partial<Result>
type Expected2 = MagicMappingType<Standalone>;

现在我想出了这个方法,但是它不能很好地工作

type _TrimToFunction<T> = T extends (...args: any[]) => any ? T : never;

// Expected has type (arg: ExampleArg) => Partial<ExampleResult> - Correct!
type Expected = _TrimToFunction<FuncOrObj>;

// Expected2 is never - Wrong!
type Expected2 = _TrimToFunction<Standalone>;

这显然是因为独立接口ExampleResult没有通过_TrimToFunction的条件,因此被映射到never。但是,如果我将_TrimToFunction更改为此:

type _TrimToFunction<T> = T extends (...args: any[]) => any ? T : (...args: any[]) => T;

映射独立接口会产生正确的结果,但是现在对于FuncOrObj类型,我得到了错误的结果:

type Expected =
  | ((arg: ExampleArg) => Partial<ExampleResult>)
  | ((...args: any[]) => Partial<Partial<ExampleArg>>)

type Expected2 = (...args: any[]) => Partial<ExampleResult>

这是由于FuncOrObj联合的第二部分未通过条件检查而被映射为“ else”类型引起的。

我想使用TS 2.8实现什么目标?

1 个答案:

答案 0 :(得分:1)

在最后一个代码段中获得意外类型的原因是,如果type参数为赤裸裸,则条件类型将在联合上分布。阅读docs以获得更多信息。

简单的解决方案是稍微改变条件。我们可以使用Extract。如果我们可以从Function中提取一个T,则返回该值;如果不能,则返回一个返回Partial<T>

的新函数。
type _TrimToFunction<T> = Extract<T, Function> extends never ? (...args: any[]) => Partial<T>: Extract<T,Function>;

// Expected has type (arg: ExampleArg) => Partial<ExampleResult> - Correct!
type Expected3 = _TrimToFunction<FuncOrObj>;

// Expected2 is (...args: any[]) => Partial<ExampleResult>
type Expected4 = _TrimToFunction<Standalone>;