这里有三种简单的类型

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正确判断valueFuncprop的类型.然而,如果我给T2加上另一个类型的union,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可以很好地使用discriminated unions

T1是受歧视的,因 for each unions 有letter个财产,而T2个则不是.解决这个问题有两种方法.

First way

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

Second way

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

Playground

经验法则:

More explanation

1)

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

我们也可以使用T extends any.这里的要点是使用条件输入法.为什么?因为当你使用keyof ({a:1}|{b:2})时,你会得到never,因为它们没有共同的属性.见here.

这意味着当你使用:

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

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

一般来说,你应该把T extends any——作为turn on distributivity[T] extends [any]——当作没有分配性的判断.

另外,你可以查看我的blog个更有趣的例子

Typescript相关问答推荐

泛型函数类型验证

需要使用相同组件重新加载路由变更数据—React TSX

泛型类型联合将参数转换为Never

仅针对某些状态代码重试HTTP请求

如何将泛型对象作为返回类型添加到类型脚本中

用于验证字符串变量的接口成员

使用订阅时更新AG网格中的行

为什么我在这个重载函数中需要`as any`?

为什么Typescript只在调用方提供显式泛型类型参数时推断此函数的返回类型?

与toast.error一起react 中的Async TUNK错误消息

如何使用TypeScrip在EXPO路由链路组件中使用动态路由?

map 未显示控制台未显示任何错误@reaction-google-map/api

为什么在这种情况下,打字脚本泛型无法正确自动完成?

换行TypeScript';s具有泛型类型的推断数据类型

通过辅助函数获取嵌套属性时保留类型

两个接口的TypeScript并集,其中一个是可选的

带动态键的 TS 功能

Next.JS-13(应用程序路由)中发现无效的中间件

NgRx 效果在 10 次错误后消失

Typescript 中可以提前返回 Typeguard 吗?