【问题标题】:Algebraic data types in TypeScriptTypeScript 中的代数数据类型
【发布时间】:2016-02-28 04:20:49
【问题描述】:

换一种说法

您将如何在 TypeScript 中键入 windowState 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!

原始问题

我如何在 TypeScript 中使用 declaretype 来描述代数数据类型?这样做的目的是描述现有的 API。

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

type Weather = 'sunny' | 'bad'

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

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

const enum Weather {
  sunny = 'sunny',
  bad = 'bad',
  windy = Symbol('windy')
}

我会认为string 常量是一个常量表达式。

【问题讨论】:

  • 对于这个特定的例子,你可能会使用enum(不过需要在一些地方转换成字符串)
  • 是的,我也会将其添加到问题中,因为 enum 并不令人满意
  • TypeScript 确实理解符号。如果您的运行时环境支持,您可以加载 lib.es6.d.ts 或复制 Symbol 接口。
  • @Kitson 是否将它们视为常量表达式?
  • TypeScript 1.8 将引入“字符串文字类型”:github.com/Microsoft/TypeScript/pull/5185

标签: typescript algebraic-data-types


【解决方案1】:

要使用枚举,你可以写一些 like this:

enum Weather {
    Sunny,
    Windy
};

let currently = Weather.Sunny;

字符串字面量

OP 要求解决此问题的另一种方式是到达TypeScript 1.8

他们会允许你做这样的事情:

type Weather = 'Sunny' | 'Windy';

【讨论】:

  • 但我需要一个type,它可以描述为几个string 常量之一。
  • 为什么需要字符串常量?
  • 有一个现有的 API,这将是一个类型,
  • 您所要求的将出现在 TypeScript 1.8 中(目前可通过 npm install typescript@next 进行测试
【解决方案2】:

TypeScript 2.0 支持可区分的联合/代数数据类型。文档是here

您可以组合字符串文字类型、联合类型、类型保护和类型别名来构建称为可区分联合的高级模式,也称为标记联合代数数据类型。 可区分联合在函数式编程中很有用。 某些语言会自动为您区分工会; 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;
}

首先我们声明我们将联合的接口。 每个接口都有一个具有不同字符串文字类型的kind 属性。 kind 属性称为 discriminanttag。 其他属性特定于每个接口。 请注意,这些接口当前是不相关的。 让我们把它们放到一个联合中:

type Shape = Square | Rectangle | Circle;

现在让我们使用有区别的联合:

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;
    }
}

在每个分支中,TypeScript 都会缩小类型。 如果您尝试使用 case 子句的值不作为任何 kind 属性出现,那么 TypeScript 将出错。

【讨论】:

  • 你能举例说明如何使用该类型的文字参数调用这样的函数吗?我想我对 Haskell 语法的错误类比感到困惑。
猜你喜欢
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-13
  • 2018-05-30
  • 2017-11-09
  • 1970-01-01
相关资源
最近更新 更多