`{a:number;之间的任何行为差异; b:字符串}`和`{a:数字}&{b:字符串}`?

时间:2019-09-24 21:33:25

标签: typescript

以下类型在TypeScript中的行为是否有所不同?

type Regular = {a: number; b: string};
type Intersection = {a: number} & {b: string};

我之所以问是因为TS不会自动将后者简化为前者(例如,当将鼠标悬停在VSCode中的类型上时),所以我想知道是否有某种行为原因导致未进行简化。我认为TS很有可能还没有实现这种简化,但是我想确保我不会对TS的工作原理有所了解。

1 个答案:

答案 0 :(得分:2)

这些类型不应的行为不同,因为它们表示相同的一组值。在大多数情况下,它们不会表现不同,但是在某些情况下,肯定存在编译器对两个表面上等效的类型进行不同处理的情况,因此我不能自信地说它们永远不会表现不同。但是我们知道他们不应该。

有一个(相当久远的)open issue,可以将这种交集合并为单个对象类型,如您所建议的那样。设计团队在related comment中说:

  
      
  • 同意建议的行为是可取的
  •   
  • T & U与它的分解形式之间可能存在一些差异?      
        
    • 我们想不起来
    •   
  •   

该问题被标记为“需要帮助”(因此他们可能会接受执行此操作的请求),但被标记为“努力:困难”,因为他们担心您天真地对自引用类型进行操作时会发生什么。我猜这可能会导致编译器的性能真的很差吗?不知道这是否仍然是一个问题。


有趣的是,由于conditional types,您可以自己在类型系统中接近编写这种类型的东西:

type RecursivelyMerge<T> = T extends Function
  ? T
  : T extends object
    ? T extends infer O ? { [K in keyof O]: RecursivelyMerge<O[K]> } : never
    : T;

然后RegularIntersection变为同一类型:

type MergedRegular = RecursivelyMerge<Regular>; // {a: number; b: string}
type MergedIntersection = RecursivelyMerge<Intersection>; // {a: number; b: string}

您也可以执行嵌套类型:

type Nested = RecursivelyMerge<
  { a: { b: { c: { d: string } } } } & { a: { b: { c: { e: number } } } }
>; 
// type Nested = { a: { b: { c: {d: string; e: number } } } }

甚至自我引用类型似乎都没问题(除了它们显示得很奇怪):

type Tree = { node: Tree[] };
type ExplodedTree = RecursivelyMerge<Tree>; 
// type ExplodedTree = { node: ...[]; } // hmm, weird
declare const t: ExplodedTree;
t.node[2].node[10].node[42].node // works fine though

所以我的猜测是,当匿名类型的交集出现时,有足够动力的人可以编写一些代码,使这种情况在编译器中自动发生,并带有足够的测试套件来证明递归类型不会使事情陷入困境,而且可能会以该语言结尾。好吧,只要一般的性能损失非常低。但这只是一个猜测。

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

Link to code