提取通用

时间:2017-09-21 00:13:51

标签: typescript mapped-types

TypeScript Mapped Types: Get element type of array类似,我有一个类型,比如:

type A = {
   Item1: Promise<string>,
   Item2: Promise<number>,
   Item3: number
}

我想从中提取以下类型:

type A' = {
   Item1: string,
   Item2: number,
   Item3: number
}

请注意其中一个字段不是Promise的复杂性。

这甚至是可能还是我只是达到了打字类型的限制?我试图摆弄映射类型和记录类型,但我无法弄明白。

更新

说我想对函数调用做同样的事情:

type A = {
  Item1: (string, number) => Promise<string>,
  Item2: () => Promise<number>,
  Item3: () => number
}

所需的类型是:

type A' = {
  Item1: (string, number) => string,
  Item2: () => number,
  Item3: () => number
}

我认为这与我陈述的第一个案例相似,但函数返回值似乎并不像我希望的那样直接。

1 个答案:

答案 0 :(得分:6)

它不完全不可能,但如果没有mapped conditional typesthe like的官方支持,它就会失败。我们来试试吧。首先,让我们设置一些类型级布尔逻辑:

type False = '0';
type True = '1';
type Bool = False | True;
type If<Cond extends Bool, Then, Else> = { '0': Else; '1': Then }[Cond];

因此,If<True, Then, Else>类型评估为Then,类型If<False, Then, Else>评估为Else

第一个问题是您需要能够确定某个类型是否为Promise。第二个是,您需要能够获得T的类型,给定Promise<T>。我将通过增加ObjectPromise<T>接口的声明以及在运行时不存在的某些幻像属性来实现此目的:

// if you are in a module you need to surround 
// the following section with "declare global {}"
interface Object {
  "**IsPromise**": False
}
interface Promise<T> {
  "**IsPromise**": True
  "**PromiseType**": T
}

那是不确定的部分。增加全局接口并不是很好,因为它们位于每个人的命名空间中。但它具有所需的行为:任何Object不是Promise的{​​{1}}属性都有False类型,而"**IsPromise**"Promise 1}}价值。此外,True的{​​{1}}属性类型为Promise<T>。同样,这些属性在运行时不存在,它们只是帮助编译器。

现在,我们可以定义"**PromiseType**",将T映射到Unpromise并保留其他任何类型:

Promise<T>

Ttype Unpromise<T extends any> = If<T['**IsPromise**'], T['**PromiseType**'], T> 映射到对象的属性:

MapUnpromise

让我们看看它是否有效:

Unpromise

成功!但是我们已经为类型做了一些相当不愉快的事情来实现它,它可能不值得。这取决于你!

希望有所帮助;祝你好运!

更新1

据我所知,遗憾的是,对函数调用执行相同的操作是不可能的。你真的需要extended typeof type query之类的东西,而且目前还不是TypeScript的一部分(无论如何都是TypeScript v2.5)。

因此,您无法从中获取类型type MapUnpromise<T> = { [K in keyof T]: Unpromise<T[K]> } 并计算type A = { Item1: Promise<string>, Item2: Promise<number>, Item3: number } type Aprime = MapUnpromise<A> // evaluates to { Item1: string; Item2: number; Item3: number; } (请注意A不是有效的标识符。如果APrime使用A',请使用你要)。但您可以创建一个基本类型,您可以从中计算AAPrime

type False = '0';
type True = '1';
type Bool = False | True;
type If<Cond extends Bool, Then, Else> = { '0': Else; '1': Then }[Cond];
type MaybePromise<Cond extends Bool, T> = If<Cond, Promise<T>, T>

我放弃了全局扩充并添加了MaybePromise<Cond, T>,其中MaybePromise<True, T>评估为Promise<T>MaybePromise<False, T>评估为T。现在,我们可以使用A获取APrimeMaybePromise<>

type ABase<Cond extends Bool> = {
  Item1: (s: string, n: number) => MaybePromise<Cond, string>,
  Item2: () => MaybePromise<Cond, number>,
  Item3: () => number
}

type A = ABase<True>;
// evaluates to { 
//   Item1: (s: string, n: number) => Promise<string>; 
//   Item2: () => Promise<number>; 
//   Item3: () => number; }


type APrime = ABase<False>;
// evaluates to { 
//   Item1: (s: string, n: number) => string; 
//   Item2: () => number; 
//   Item3: () => number; }

所以这个有效!但是我建议的重构可能不适合你的用例。这取决于您首先获得A类型的方式。哦,那是我能做的最好的事情。希望它有所帮助。祝你好运!