以下类型在TypeScript中的行为是否有所不同?
type Regular = {a: number; b: string};
type Intersection = {a: number} & {b: string};
我之所以问是因为TS不会自动将后者简化为前者(例如,当将鼠标悬停在VSCode中的类型上时),所以我想知道是否有某种行为原因导致未进行简化。我认为TS很有可能还没有实现这种简化,但是我想确保我不会对TS的工作原理有所了解。
答案 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;
然后Regular
和Intersection
变为同一类型:
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
所以我的猜测是,当匿名类型的交集出现时,有足够动力的人可以编写一些代码,使这种情况在编译器中自动发生,并带有足够的测试套件来证明递归类型不会使事情陷入困境,而且可能会以该语言结尾。好吧,只要一般的性能损失非常低。但这只是一个猜测。
哦,希望能有所帮助;祝你好运!