差异联合类型和区分联合打字稿/ F#

Posted

技术标签:

【中文标题】差异联合类型和区分联合打字稿/ F#【英文标题】:Difference union types and discriminated unions typescript/F# 【发布时间】:2020-08-22 01:50:48 【问题描述】:

所以我正在阅读关于联合类型的 Typescript 官方文档,我认为它与 F# 中的“可区分联合”相同(假设它们具有不同的语法但相同的概念),因为我有 F# 背景和鉴于两者都得到了微软的支持。但是查看文档,F# 并没有真正区分“联合类型”和“有区别的联合”:https://fsharpforfunandprofit.com/posts/discriminated-unions/

但是,Typescript 确实区分了这两个概念:

联合类型:https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types

歧视工会:https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions

所以我想知道这些概念本身是否真的有区别,或者只是一些依赖于语言的概念?

目前我的理解是,F# 中的联合类型也是可区分联合,因为您可以使用匹配表达式和解构来区分联合类型。

但是,您不能使用 Typescript 进行区分,因为该语言没有提供特定的表达式来做到这一点,因此您需要通过一个值来区分,所有联合类型都具有判别式。这是正确的吗?

【问题讨论】:

是的,TS 中的判别式只是您选择的任意对象属性。对于有区别的或标记的联合,您不需要这个,因为类型本身携带了这些信息。由于在编译期间不会删除标记,因此您可以在运行时对其进行模式匹配。 【参考方案1】:

类型联合(A | B) 中的操作数都是类型,而可区分联合type U = A | B 中的情况都是U 类型的构造函数,而不是类型本身。 U 类型的值在运行时被标记,因此您可以区分可能的情况。

一个结果是,有区别的联合可以以联合类型可能不会嵌套的方式嵌套。联合类型系统中某些类型A 的可选值可能表示为

type A? = (A | null)

其中nullnull 值的单例类型。

对于有区别的联合,它通常表示为

type a' option = Some of 'a | None 

这个公式的价值

let o: int option option = Some None

不能用联合类型表示,因为(A?)? == (A | null) | null == A | null == A?

【讨论】:

当然可以extend untagged unions 我真的很喜欢你基于类型构造器思想的解释,这更有意义。但是为什么嵌套联合不能与联合类型一起使用,谁来“减少”你展示的类型?以及为什么有区别的联合确实适用于嵌套类型?【参考方案2】:

主要区别在于,Typescript Union Type 实际上是 F# Discriminator Union 的超集。

TypeScript 联合类型 = 未标记 联合类型。 F# 可区分联合 = 标记联合类型。

换句话说,可以在 F# 中建模的每个可区分联合都可以在 Typescript 联合类型中同构地建模,但反之则不然。

例如,F#中的以下可区分联合:

type a' Option = Some of 'a | None 

可以在 Typescript 中同构建模为:

type Option<T> = tag: 'Some', value: T | tag: 'None'

但是,以下 Typescript 联合类型无法在 F# 中进行同构建模:

type UserInput = number | string

这里的主要区别是 TypeScript 联合类型不需要标记,而 F# 联合类型必须标记。

因此,我们可以看到 TypeScript 实际上比 F# 更灵活,但这并不是没有代价的,未标记的联合实际上是有漏洞的,这意味着有些类型的联合会导致 TypeScript 无法进行类型检查。

就像非类型 lambda 演算是类型化 lambda 演算的超集,但类型 lambda 演算更容易证明正确。

【讨论】:

所以联合类型基本上允许对可能的多种类型使用类型别名,这是有区别的联合不能做到的,它们只能用于一种类型。正如@Lee 在他的回答中提到的那样,对于有区别的联合,我们需要类型构造函数,它们是“案例”或标记标签。定义一个有区别的联合就是为一个类型指定不同的类型构造函数。而对于联合类型,我们可以定义其他类型的类型别名。

以上是关于差异联合类型和区分联合打字稿/ F#的主要内容,如果未能解决你的问题,请参考以下文章

打字稿是不是允许接口和字符串联合类型?

打字稿:检查类型是不是为联合

函数的打字稿联合/交集类型

从类型联合定义打字稿函数签名[重复]

在这种情况下,打字稿可以做联合类型断言吗?

打字稿中具有联合类型键的松散类型对象