繁体   English   中英

在 TypeScript 中组合并集和交集类型时的参数类型解析

[英]Param type resolution when combining union and intersection types in TypeScript

这里有3种简单的类型

type T1 =
  | { letter: 'a'; valueFunc: (prop: number) => void; valueType: number }
  | { letter: 'b'; valueFunc: (prop: string) => void; valueType: string }

type T2 = { base: 'low' }

type T3 = T1 & T2

和 2 个简单的定义

const var1: T3 = { letter: 'b', base: 'low', valueFunc: (prop) => {}, valueType: 'empty' }

const var2: T3 = { letter: 'a', base: 'low', valueFunc: (prop) => {}, valueType: 0 }

这可以按预期完美运行。 TS 正确评估valueFunc中的prop类型。 但是,如果我向T2添加另一个类型联合,则 TS 不再能够解析prop但它仍然可以解析valueType

修改类型

type T1 =
  | { letter: 'a'; valueFunc: (prop: number) => void; valueType: number }
  | { letter: 'b'; valueFunc: (prop: string) => void; valueType: string }

type T2 = { base: 'low' } | {noise: 'high'}

type T3 = T1 & T2

const var1: T3 = { letter: 'b', base: 'low', valueFunc: (prop) => {}, valueType: 'empty' }

const var2: T3 = { letter: 'a', noise: 'high', valueFunc: (prop) => {}, valueType: 0 }

这是为什么? 我错过了什么?

TypeScript 与有区别的联合工作得很好

T1是有区别的,因为每个联合都有letter属性,而T2没有。 您有两种方法可以解决此问题。

第一种方式只需将discriminator器添加到T2 ,例如:

type T2 = { type: '1', base: 'low' } | { type: '2', noise: 'high' }

第二种方式使您的T2联合更加严格。 有关更多说明,请参阅此答案

type T1 =
  | { letter: 'a'; valueFunc: (prop: number) => void; }
  | { letter: 'b'; valueFunc: (prop: string) => void; }


type UnionKeys<T> = T extends T ? keyof T : never;

type StrictUnionHelper<T, TAll> =
  T extends any
  ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;

type StrictUnion<T> = StrictUnionHelper<T, T>

type T2 = StrictUnion<{ base: 'low' } | { noise: 'high' }>

type T3 = T1 & T2

const var1: T3 = { letter: 'b', base: 'low', valueFunc: (prop) => { } } // prop is string

const var2: T3 = { letter: 'a', noise: 'high', valueFunc: (prop) => { } } // prop is number

操场

经验法则:如果您有一个联合,其中每个对象都不同并且没有任何共同点 - 添加鉴别器。

更多解释

1)

为什么我们使用UnionKeys而不是keyof T

我们也可以使用T extends any 这里的要点是使用条件类型进行分配 为什么 ? 因为当您使用keyof ({a:1}|{b:2})时,您将never不会得到,因为它们不共享公共属性。 这里

这意味着当您使用时:

type UnionKeys<T> = T extends any ? keyof T : never;

keyof T单独应用于联合中的每个元素,而不是仅应用于整个联合,因为我们在这里使用了T extends any

一般来说,您应该将T extends any - 作为turn on distributivity性和[T] extends [any] - 作为检查它而不进行分配性。

PS您可以查看我的博客以获取更多有趣的示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM