为什么TypeScript有时只将不可能的交叉点视为';从不';?

为什么TypeScript有时只将不可能的交叉点视为';从不';?,typescript,set-intersection,Typescript,Set Intersection,TypeScript有时会决定两个类型(如果相交)没有任何兼容的值。此空交叉点称为从不,表示无法提供满足这两种类型的值: type Bread = { shape: "loafy" }; type Car = { shape: "carish" }; // Contradiction1: Immediately resolved to 'never' type Contradiction1 = Bread & Car; 然而,这似乎是不一致的。如果冲突属性不在类型的顶层,则T

TypeScript有时会决定两个类型(如果相交)没有任何兼容的值。此空交叉点称为
从不
,表示无法提供满足这两种类型的值:

type Bread = {
  shape: "loafy"
};
type Car = {
  shape: "carish"
};

// Contradiction1: Immediately resolved to 'never'
type Contradiction1 = Bread & Car;
然而,这似乎是不一致的。如果冲突属性不在类型的顶层,则TypeScript将丢失该属性,并且其行为方式与我预期的不同:

// Wrap the contradicting types
type Garage = { contents: Car };
type Breadbox = { contents: Bread };

// Contradiction2: Garage & Breadbox
// Expected: Should immediately reduce to never
type Contradiction2 = Garage & Breadbox;

这是虫子吗?为什么TypeScript会有这种行为?

这是预期的行为,因为TypeScript中的属性路径在更改类型的过程中可以任意深入。例如,写这样的东西是完全合法的:

declare class Boxed<T> {
  contents: T;
  doubleBoxed: Boxed<this>
};
declare const b: Boxed<string>
// m: Boxed<Boxed<Boxed<Boxed<Boxed<string>>>>>
const m = b.doubleBoxed.doubleBoxed.doubleBoxed.doubleBoxed;
// I am here to cause trouble.
type M<T, S> = T extends { nested: { nested: { nested: any } } } ?
  S :
  { el: T, nested: M<{ nested: T }, S> };

type F1 = {
  prop: M<F1, "foo">
};
type F2 = {
  prop: M<F2, "bar">
};

declare const f1: F1;
// f1.prop.nested.nested.nested: "foo"
f1.prop.nested.nested.nested;

declare const f12: F1 & F2;

// OK, infinitely
f12.prop.el.prop.el.prop.el.prop.el.prop;
// 'never' at depth 4...
f12.prop.nested.nested.nested;
真的没有办法预测你需要去哪里寻找可能导致
never
的表达式,
M
的定义没有给我们任何提示;你必须作为一个人真正理解这段代码,才能知道在哪里可以找到嵌套的
never


事实上,如果您可以为任意深度的属性访问“正确地”解决这个问题,您可以通过构造执行算术的类型(这已经是可能的)来做一些事情。显然,这是不可能的,因此TypeScript不会尝试超出生成类型的顶级属性的容易解决的情况。

同时还有一个费马最后定理的简单证明:)