TypeScript中的代数数据类型

ᆼᆺᆼ*_*ᆼᆺᆼ 9 algebraic-data-types typescript

另一种方式:

如何windowState在TypeScript中键入DOM属性?

已解决(在TypeScript 2中):

declare var windowState: WindowState
const enum WindowState {
  STATE_MAXIMIZED = 1,
  STATE_MINIMIZED = 2,
  STATE_NORMAL = 3,
  STATE_FULLSCREEN = 4
}
...
var windowState = 5 // Type Error, as expected!
Run Code Online (Sandbox Code Playgroud)

原始问题:

我怎么declare一个type在打字稿,以便它描述了一个代数数据类型?这样做的目的是描述现有的API.

当我尝试以下操作时,TypeScript显然会抱怨type is expected:

type Weather = 'sunny' | 'bad'
Run Code Online (Sandbox Code Playgroud)

我有一个想法是使用JavaScript 2015 Symbol,但TypeScript似乎并不知道这些.

另一个想法是使用一个enum,但TypeScript抱怨说member initializer must be constant expression:

const enum Weather {
  sunny = 'sunny',
  bad = 'bad',
  windy = Symbol('windy')
}
Run Code Online (Sandbox Code Playgroud)

我原以为string常量是一个常量表达式.

Dan*_*ser 16

TypeScript 2.0支持有区别的联合/代数数据类型.文档在这里.

您可以组合字符串文字类型,联合类型,类型保护和类型别名来构建称为区分联合的高级模式,也称为标记联合代数数据类型.受歧视的联合在函数式编程中很有用.有些语言会自动为您区分工会; 而TypeScript则建立在当今存在的JavaScript模式之上.有三个要素:

  1. 具有公共文字(或枚举)属性的类型 - 判别式.
  2. 采用这些类型的集的类型别名 - 联合.
  3. 公共财产上的警卫.

开始吧:

interface Square {
    kind: "square";
    size: number;
}
interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}
interface Circle {
    kind: "circle";
    radius: number;
}
Run Code Online (Sandbox Code Playgroud)

首先,我们声明将要联合的接口.每个接口都有一个kind具有不同字符串文字类型的属性.该kind属性称为判别式标记.其他属性特定于每个接口.请注意,接口当前不相关.让我们把他们变成一个联盟:

type Shape = Square | Rectangle | Circle;
Run Code Online (Sandbox Code Playgroud)

现在让我们使用受歧视的联盟:

function area(s: Shape) {
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.height * s.width;
        case "circle": return Math.PI * s.radius ** 2;
    }
}
Run Code Online (Sandbox Code Playgroud)

在每个分支中,TypeScript将缩小类型.如果您尝试使用具有case不作为任何kind属性存在的值的子句,则TypeScript将出错.

  • 你能举例说明如何使用那种类型的文字参数调用这样的函数吗?我想我对 Haskell 语法的错误类比感到困惑。 (2认同)
  • “支持”带有(自由字符串)判别式...但是总比没有好,是的... (2认同)