Typescript 差异联合类型和区分联合类型脚本/F#

Typescript 差异联合类型和区分联合类型脚本/F#,typescript,functional-programming,f#,union-types,Typescript,Functional Programming,F#,Union Types,所以我读了Typescript关于工会类型的官方文档,我认为这和F#中的“歧视工会”是一样的(尽管它们有不同的语法,但概念相同),因为我有F#背景,而且两者都有微软的支持。但看看这些文件,F#并没有真正区分“工会类型”和“歧视工会”: 但是,Typescript确实区分了这两个概念: 联合类型: 受歧视的工会: 所以我想知道这些概念本身是否真的有区别,或者仅仅是一些依赖于语言的概念 到目前为止,我所了解的是F#中的并集类型也是有区别的并集,因为可以使用匹配表达式和解构来区分并集类型 但是,您不能

所以我读了Typescript关于工会类型的官方文档,我认为这和F#中的“歧视工会”是一样的(尽管它们有不同的语法,但概念相同),因为我有F#背景,而且两者都有微软的支持。但看看这些文件,F#并没有真正区分“工会类型”和“歧视工会”:

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

联合类型:

受歧视的工会:

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

到目前为止,我所了解的是F#中的并集类型也是有区别的并集,因为可以使用匹配表达式和解构来区分并集类型


但是,您不能使用Typescript进行区分,因为该语言没有提供具体的表达式来进行区分,因此您需要通过所有联合类型都具有的值来进行区分,即区分器。这是否正确?

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

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

type A? = (A | null)
type a' option = Some of 'a | None 
其中
null
null
值的单例类型

对于一个受歧视的联盟,它通常被表示为

type A? = (A | null)
type a' option = Some of 'a | None 
用这个公式计算出的值

let o: int option option = Some None

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

主要区别在于,Typescript联合类型实际上是F#判别联合的超集

类型脚本联合类型=未标记的联合类型。
F#区分的联合=标记的联合类型

换句话说,每一个可以用F#建模的有区别的并集都可以用Typescript并集类型进行同构建模,但反之则不然

例如,F#中的以下歧视并集:

可以在Typescript中进行同构建模,如下所示:

type Option<T> = {tag: 'Some', value: T} | {tag: 'None'}
这里的主要区别是TypeScript联合类型不需要标记,但是F#联合类型必须标记

因此,我们可以看到TypeScript实际上比F#更灵活,但是这并不是没有成本的,未标记的联合实际上是多孔的,这意味着有一些类型联合,TypeScript将无法进行类型检查


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

是的,TS中的判别式只是您选择的一个偶然对象属性。对于区分的或标记的联合,您不需要这样做,因为类型本身携带这些信息。由于标记在编译过程中不会被删除,所以您可以在运行时对其进行模式匹配。当然,您可以。我非常喜欢您基于类型构造函数思想的解释,这更有意义。但是,为什么嵌套的联合不能与联合类型一起工作呢?如您所示,是谁“简化”了类型?为什么有区别的联合可以与嵌套类型一起工作呢?所以联合类型基本上允许对可能的多个类型使用类型别名,而有区别的联合不能这样做,它们只能对一种类型使用类型别名。正如@Lee在他的回答中提到的,对于有区别的联合,我们需要类型构造函数,即“cases”或标记标签。定义区分的联合就是为一个类型指定不同的类型构造函数。对于联合类型,我们可以定义其他类型的类型别名。