Typescript “{a:number;b:string}”和“{a:number}”之间的任何行为差异&;{b:string}`?

Typescript “{a:number;b:string}”和“{a:number}”之间的任何行为差异&;{b:string}`?,typescript,Typescript,以下类型在TypeScript中的行为是否有任何不同 type Regular={a:number;b:string}; 类型交叉={a:number}&{b:string}; 我这样问是因为TS不会自动将后者简化为前者(例如,当鼠标悬停在VSCode中的类型上时),所以我想知道是否有行为原因导致没有进行简化。我认为TS很可能还没有实现这种简化,但我想确保我没有遗漏关于TS工作原理的一些微妙之处 这些类型的行为不应该不同,因为它们代表同一组值。在大多数情况下,它们的行为并不不同,但确实存在两种

以下类型在TypeScript中的行为是否有任何不同

type Regular={a:number;b:string};
类型交叉={a:number}&{b:string};
我这样问是因为TS不会自动将后者简化为前者(例如,当鼠标悬停在VSCode中的类型上时),所以我想知道是否有行为原因导致没有进行简化。我认为TS很可能还没有实现这种简化,但我想确保我没有遗漏关于TS工作原理的一些微妙之处

这些类型的行为不应该不同,因为它们代表同一组值。在大多数情况下,它们的行为并不不同,但确实存在两种表面上等价的类型被编译器区别对待的情况,因此我不能自信地说它们的行为永远不会不同。但我们知道他们不应该

正如您所建议的,将此类交点合并为单个对象类型是一个长期存在的问题。在一份报告中,设计团队的注释说:

  • 同意提议的行为是可取的
  • T&U
    与其分解形式之间可能存在一些差异?
    • 我们想不出什么
该问题被标记为“需要帮助”(因此他们可能会接受这样做的请求),但被标记为“努力:困难”,因为他们担心当您天真地对自引用类型执行此操作时会发生什么。我想,这可能会导致编译器执行得非常糟糕?不确定这是否仍然是一个问题


有趣的是,多亏了,您可以自己在类型系统中编写这种类型的东西:

type RecursivelyMerge<T> = T extends Function
  ? T
  : T extends object
    ? T extends infer O ? { [K in keyof O]: RecursivelyMerge<O[K]> } : never
    : T;
您也可以执行嵌套类型:

type Nested = RecursivelyMerge<
  { a: { b: { c: { d: string } } } } & { a: { b: { c: { e: number } } } }
>; 
// type Nested = { a: { b: { c: {d: string; e: number } } } }
type Nested=RecursivelyMerge<
{a:{b:{c:{d:string}}}}&{a:{b:{c:{e:number}}}
>; 
//类型Nested={a:{b:{c:{d:string;e:number}
甚至自我引用类型似乎也没有问题(除了它们显示得很奇怪):

type Tree={node:Tree[]};
类型ExplodedTree=递归合并;
//键入ExplodedTree={node:…[];}//hmm,奇怪
声明常量t:爆炸树;
t、 节点[2]。节点[10]。节点[42]。节点//工作正常

因此,我猜测,有足够动机的人可以编写一些代码,当匿名类型的交集出现时,在编译器中自动实现这一点,并有足够的测试套件来证明递归类型不会使事情陷入困境,并且它可能最终会出现在语言中。好吧,只要表现的惩罚一般是很低的。不过这只是猜测而已

哦,好吧,希望这有帮助;祝你好运


在某些情况下,交叉口的行为与统一类型不同,尤其是较弱的类型:
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