与较新版本相比,Typescript Exclude<> 在 3.8 和之前的版本中表现不同

Typescript Exclude<> behaves differently in 3.8 and previous compared to newer versions

我注意到与新版本相比,在 3.8 版及之前的版本中使用 Typescript 中的 Exclude 时有所不同。

考虑以下示例:

interface Layer {
    id: string;
}

export enum LayerType {
    Text,
    Image,
}

interface ImageLayer extends Layer {
    src: string,
    layerType: LayerType.Image;
}
interface TextLayer extends Layer {
    text: string,
    layerType: LayerType.Text;
}

type Layercombined = ImageLayer & TextLayer;
type IgnoredProperties = "layerType";

type WithoutLayerType = {
    [key in Exclude<keyof Layercombined, IgnoredProperties>]: string;
};
const test: WithoutLayerType = {
    id: "17",
    src: "test",
    text: "test",
    layerType: "type",
};

将对象分配给 const test 直到 3.8 才会失败,IMO 理所当然地抱怨 layerType 在 WithoutLayerType 上不存在,因为它被排除在外。在 3.9 和更新版本中,分配很好。 对我来说这感觉像是一个错误,但我敢肯定这其中有些我不明白的地方:) 或许有人可以赐教!

问题的出现是因为 TypeScript 改变了它对 intersection and optional properties in 3.9 类型检查的处理方式。

在 3.9 之前,LayeredCombined 的类型结果将是所有属性的组合。 3.9以后,结果是never,因为layerType的类型冲突(一个是LayerType.Image,另一个是 LayerType.Text).

因为 LayeredCombined 现在是类型 never,来自 keyof Layercombined[=31] 的字符串文字的类型=] 不包含 ImageLayer 或 TextLayer 的任何属性,因此不能排除任何内容。

最简单的解决方法是重新定义 Layercombined,如下所示:

type Layercombined = Partial<ImageLayer> & Partial<TextLayer>;

这将为您提供所有键,因为现在 layerType 将具有一个可能的值,未定义