与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
}
我认为这与我陈述的第一个案例相似,但函数返回值似乎并不像我希望的那样直接。
答案 0 :(得分:6)
它不完全不可能,但如果没有mapped conditional types或the 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>
。我将通过增加Object
和Promise<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>
T
将type Unpromise<T extends any> = If<T['**IsPromise**'], T['**PromiseType**'], T>
映射到对象的属性:
MapUnpromise
让我们看看它是否有效:
Unpromise
成功!但是我们已经为类型做了一些相当不愉快的事情来实现它,它可能不值得。这取决于你!
希望有所帮助;祝你好运!
据我所知,遗憾的是,对函数调用执行相同的操作是不可能的。你真的需要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'
,请使用Aʹ
你要)。但您可以创建一个基本类型,您可以从中计算A
和APrime
:
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
获取APrime
和MaybePromise<>
:
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
类型的方式。哦,那是我能做的最好的事情。希望它有所帮助。祝你好运!