如何查看Typescript类型的完整展开合同?

4si2a6ki  于 2022-12-30  发布在  TypeScript
关注(0)|答案(2)|浏览(151)

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

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
}

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

kxkpmulp

kxkpmulp1#

IntelliSense显示的类型的快速信息通常会留下一些需要改进的地方;对于任何给定的类型,你通常会得到一个单一的表示,这对于你的目的来说可能会变得过于简洁甚至过于冗长。2有一些建议可以使它更加灵活(例如,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中,然后是类似于标识的mapped type,它迭代复制的类型的属性。
条件类型推断在概念上是无操作的,但它用于分配联合类型,并强制编译器计算条件的"true"分支(如果您重新定义Expand<T>而不使用它,有时编译器将只 * 输出 * Map的类型{[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;
 } */

如你所愿。
链接到代码

j0pj023g

j0pj023g2#

只是补充jcalz's answer与版本的工作与函数。
为了测试,我在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;

这给出:

对象仍然工作正常:
第一节第三节第一节第一节第四节第一节

相关问题