表达式
交集
类似于其 TypeScript 对标,交集将两个现有的 Type 组合起来,创建一个新的 Type,它强制执行两者的约束。
并集
所有并集都会自动进行判别,以优化检查时间和错误消息的清晰度。
一个可能对相同数据应用不同 morph 的并集会抛出 ParseError!
了解此限制背后的集合论
如果您对基于集合的类型相对陌生,这个错误可能令人望而却步,但如果您花点时间思考这个例子,就会清楚为什么不允许这样做。bad 的逻辑本质上是:
- 如果输入是一个对象,其中
box是string,则解析并将其作为数字返回 - 如果输入是一个对象,其中
box是string,则将其作为字符串返回
没有办法为这种类型确定性地返回输出,而不牺牲并集操作符的交换性。
sameError 可能看起来更无害,但对于像 { a: "1", b: "2" } 这样的输入,它有同样的问题。
- 左分支只会解析
a,导致{ a: 1, b: "2" } - 右分支只会解析
b,导致{ a: "1", b: 2 }
品牌
向现有类型添加一个仅限类型的符号,这样只有直接验证的值才能满足它。
品牌是一种很好的方式来表示 TypeScript 范围之外的约束,但请记住,它们不会改变运行时强制执行的任何内容!
有关品牌的一般信息,请查看 Josh Goldberg 的这篇优秀文章。
窄化
窄化表达式允许您添加自定义验证逻辑和错误消息。您可以在它们的介绍部分中阅读更多内容。
如果窄化的返回类型是一个类型谓词,那么它将反映在推断的 Type 中。
Morph
Morph 允许您在验证后转换数据。您可以在它们的介绍部分中阅读更多内容。
To
如果 morph 返回一个 ArkErrors 实例,则验证将使用该结果失败,而不是将其视为值。这特别适用于将其他 Type 用作 morph 来验证输出或链式转换。
为了使这更容易,有一个特殊的 to 操作符,可以管道到解析定义,而无需将其包装在 type 中使其成为函数:
单元
虽然嵌入的字面量语法 通常是定义确切原语值的理想选择,但 === 和 type.unit 可以帮助引用像 symbol 这样的非可序列化值。
枚举
type.enumerated 根据允许值的列表定义一个 Type。如果提供单个值,它等价于 type.unit。
valueOf
type.valueOf 从 TypeScript enum 或类似 enum 的对象定义一个 Type。
现代 TypeScript 中应避免使用 `enum`
随着时间推移,TS 已远离影响最终输出的 .js 的特性,包括 enum。
随着 --erasableSyntaxOnly 选项 的引入,以促进类型剥离,enum 不再被视为最佳实践。
type.valueOf 主要存在于与依赖 enum 的遗留代码集成,但如果您有选择,请优先通过 ["tupleLiterals"] as const、 { objectLiterals: true } as const 或直接通过 type.enumerated 透明地定义值集。
它几乎等价于 type.enumerated(...Object.values(o))。唯一的例外是当对象有一个具有数字值的条目,以及一个将该值作为键映射回原始条目的条目时:
注意 EquivalentObject 不包括 "numeric",因为它反转了数字值条目。
我们推荐 type.enumerated 作为将值引用转换为 Type 的更透明选项。然而,如果您的对象上不存在所述的反转条目对,您可以安全地使用 type.valueOf。
元数据
元数据允许您将任意元数据与您的类型关联。
某些元数据直接被 ArkType 消费,例如 description 在构建错误消息时默认被引用。
其他属性是可内省的,但默认不被内部使用。
强制转换
有时,您可能希望直接指定 Type 应该如何被推断,而不影响运行时行为。在这些情况下,您可以使用强制转换表达式。
括号
默认情况下,ArkType 的操作符遵循与 TypeScript 相同的优先级。就像在 TypeScript 中一样,这可以通过将表达式包裹在括号中来覆盖。
this
this 是一个特殊关键字,可用于创建引用当前定义根部的递归类型。
从作用域内部引用 this 将导致 ParseError。对于作用域定义内的类似行为,只需按名称引用别名: