我如何看到一个类型的完整的扩展合同?

如果我有一个类型的集合,看起来有点像这样:

type ValidValues = string | number | null
type ValidTypes = "text" | "time" | "unknown"


type Decorated = {
name?: string | null
type?: ValidTypes
value?: ValidValues
title: string
start: number
}


type Injected = {
extras: object
}


// overriding the types from Decorated
type Text = Decorated & Injected & {
name: string
type: "text"
value: string
}

我的实际代码还有更多内容,但这里展示了核心思想。我不想只有相信自己才能处理好类型之间的关系。我希望工具能够向我展示 Text的类型定义在类型代数之后“计算”到什么程度。

因此,对于上面的示例,我希望在 Text中指定的字段将覆盖以前在 Decorated类型中进行的声明,并且假设的工具提示的输出应该向我显示如下内容:

{
name: string
type: "text"
value: string
title: string
start: number
extras: object
}

有什么方便的方法可以得到这些信息吗?

12899 次浏览

使用 智能感应显示的类型的快速信息通常会留下一些需要的东西; 对于任何给定的类型,您通常都会得到一个单独的表示,这对于您的目的来说可能过于简洁,甚至过于冗长。有一些建议可以使它更加灵活(例如,Microsoft/TypeScript # 25784Microsoft/TypeScript # 28508) ,这样用户就可以在他们的 IDE 中扩展/折叠类型定义。但我不知道他们是否会在不远的将来采取行动,所以我们不要等待了。


下面是一个类型别名,我有时会用它来按照你所说的方式展开一个类型:

// expands object types one level deep
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;


// expands object types recursively
type ExpandRecursively<T> = T extends object
? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
: T;

它们使用 条件类型推断条件类型推断将类型 T“复制”到一个新的类型变量 O中,然后使用一个类似标识的 映射类型来遍历复制类型的属性。

条件类型推断在概念上是一个 no-op,但是它用于 分布式联合类型分布式联合类型并强制编译器计算条件的“ true”分支(如果你重新定义 Expand<T>而不使用它,有时编译器将仅仅 输出映射类型 {[K in keyof RelevantType]: RelevantType[K]},这不是你想看到的)。

ExpandExpandRecursively之间的区别在于,它是否应该按原样显示属性类型(Expand) ,或者它是否应该 扩张显示属性类型(ExpandRecursively)。在递归的情况下,不要试图深入到基本类型,这有所帮助,这就是为什么包含 T extends object条件的原因。


好吧,让我们看看用在你这种人身上会发生什么。我们不需要 ExpandRecursively在你的情况下,但我们 可以使用它... 它给出了相同的结果:

type ExpandedText = Expand<Text>;

当我们在 IDE (TypeScript Playground 和 VSCode)中悬停时,它会显示如下:

/* type ExpandedText = {
name: string;
type: "text";
value: string;
title: string;
start: number;
extras: object;
} */

如你所愿,希望能有所帮助,祝你好运!

链接到代码

只是在 Jcalz 的回答中添加了与函数一起工作的版本。

为了测试,我在 Text类型中添加了一个 subobject键,并添加了一个函数接口:

type Text = Decorated &
Injected & {
name: string;
type: "text";
value: string;
subobject: Injected;
};


interface SomeFunction {
(...args: Text[]): Injected & { error: boolean };
}

修改后的助手:

export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: Expand<A>) => Expand<R>
: T extends infer O
? { [K in keyof O]: O[K] }
: never;


export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T;

这意味着:

enter image description here

expanded once type hover

recursive type hover

对象仍然可以正常工作:

enter image description here enter image description here