配置

开箱即用的出色体验是 ArkType 的核心目标,包括安全的默认设置和针对复杂错误的实用消息。

然而,当您需要不同行为时,能够以适当的粒度轻松配置它同样重要。

级别

级别适用对象示例
default所有 Type 的内置默认值
global应用配置后解析的所有 Type
config.ts
import { configure } from "arktype/config"
// use the "arktype/config" entrypoint
configure({ numberAllowsNaN: true })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

type.number.allows(Number.NaN) // true
scope在配置的 Scope 中解析的所有 Type
const  = (
	{ User: { age: "number < 100" } },
	{
		max: {
			actual: () => "unacceptably large"
		}
	}
)
const  = .export()
// ArkErrors: age must be less than 100 (was unacceptably large)
.User({ name: "Alice", age: 101 })
const  = .type({
	age: "number <= 100"
})
// ArkErrors: age must be at most 100 (was unacceptably large)
parsedAfter({ age: 101 })
type由配置的 Type 浅层引用的所有 Type
// avoid logging "was xxx" for password
const  = ("string >= 8").configure({ actual: () => "" })
const  = ({
	email: "string.email",
	password: 
})
// ArkErrors: password must be at least length 8
const  = User({
	email: "david@arktype.io",
	password: "ez123"
})

某些选项仅适用于特定级别,如相应的输入类型所反映的。

对于全局配置,请在使用单独文件中的 `"arktype/config"` 入口点!

如果您需要配置应用于内置关键字(对于像 jitlessnumberAllowsNaNdateAllowsInvalid 这样的选项很重要),您应该在从 "arktype" 导入任何内容之前,从 "arktype/config" 导入并使用 configure

否则,在您的配置应用时,关键字已经被解析!

错误

为了允许自定义错误与复合错误(例如 unionintersection)的内置逻辑无缝集成,ArkType 支持一组可组合的选项:

可选描述示例
description

✅ 约束的摘要,可以完成“必须是 ___”这样的短语

🥇 被其他元数据重用,并且应该是您自定义消息的首选

const  = type.string.atLeastLength(8).describe("a valid password")
// ArkErrors: must be a valid password
const  = Password("ez123")
expected

✅ 一个接受错误上下文的函数,并返回格式为“必须是 ___”的字符串

✅ 特定于错误,并在这些情况下优先于 description

const  = type.string.atLeastLength(8).configure({
	expected: ctx =>
		ctx.code === "minLength" ? `${ctx.rule} characters or better` : "way better"
})
// ArkErrors: must be 8 characters or better (was 5)
const  = Password("ez123").toString()
// ArkErrors: must be way better (was a number)
const  = Password(12345678).toString()
actual

✅ 一个接受导致错误的数据的函数,并返回格式为“(was ___)”的字符串

✅ 如果返回空字符串,消息的 actual 部分将被省略

const  = ("string >= 8").configure({ actual: () => "" })
// ArkErrors: must be at least length 8
const  = Password("ez123")
problem

✅ 一个接受 expectedactual 的结果以及其他上下文的函数,并返回问题的完整描述,例如“必须是字符串 (was a number)”

❌ 可能不适用于像 union 这样的复合错误

const  = ("string >= 8").configure({
	problem: ctx => `${ctx.actual} isn't ${ctx.expected}`
})
// ArkErrors: 5 isn't at least length 8
const  = Password("ez123")
// ArkErrors: a number isn't a string
const  = Password(12345678)
message

✅ 一个接受 problem 的结果以及其他上下文的函数,并返回包括发生路径的问题的完整描述

❌ 可能不适用于像 union 这样的复合错误

const  = ({
	password: "string >= 8"
}).configure({
	message: ctx =>
		`${ctx.propString || "(root)"}: ${ctx.actual} isn't ${ctx.expected}`
})
// ArkErrors: (root): a string isn't an object
const  = User("ez123")
// `.configure` only applies shallowly, so the nested error isn't changed!
// ArkErrors: password must be at least length 8 (was 5)
const  = User({ password: "ez123" })

按代码

错误也可以通过其关联的 code 属性在 scopeglobal 级别进行配置。

例如:

const  = type.module(
	{ isEven: "number%2" },
	{
		divisor: {
			// the available `ctx` types will include data specific to your errors
			expected: ctx => `% ${ctx.rule} !== 0`,
			problem: ctx => `${ctx.actual} ${ctx.expected}`
		}
	}
)
// ArkErrors: 3 % 2 !== 0
.isEven(3)

ArkErrors

对于像 i18n 这样超出此可组合消息配置范围的用例,验证失败时返回的 ArkErrors 数组包含可以通过像 .hasCode("divisor") 这样的调用进行判别的 ArkError 实例,并且包含特定于该错误类型的上下文数据,以及每个可组合错误部分的 getter。

这些 ArkError 实例可以任意转换并与国际化库组合。这仍然是我们正在调查和记录的主题,因此请随时提出任何问题或反馈!

关键字

string.email 这样的内置关键字可以进行全局配置。

这对于在不需要创建自己的别名或包装器的情况下自定义错误消息非常有帮助。

config.ts
import { configure } from "arktype/config"

configure({
	keywords: {
		string: "shorthand description",
		"string.email": {
			actual: () => "definitely fake"
		}
	}
})
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

const  = type({
	name: "string",
	email: "string.email"
})

const  = User({
	// ArkErrors: name must be shorthand description (was a number)
	name: 5,
	// ArkErrors: email must be an email address (was definitely fake)
	email: "449 Canal St"
})

您在这里提供的选项与直接 配置 Type 使用的选项相同,并且也可以 在类型级别扩展以包含自定义元数据

Clone

默认情况下,在应用 morph 之前,ArkType 将使用内置的 deepClone 函数深度克隆原始输入值,该函数试图对保留原型等做出合理的假设。deepClone 的实现可以在 这里 找到。

您可以将替代的克隆实现提供给 clone 配置选项。

config.ts
import { configure } from "arktype/config"

configure({ clone: structuredClone })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

// will now create a new object using structuredClone
const  = type({
	age: "string.numeric.parse"
})

要直接变异输入对象,您可以将 clone 配置选项设置为 false

config.ts
import { configure } from "arktype/config"

configure({ clone: false })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

const  = type({
	age: "string.numeric.parse"
})

const  = {
	age: "42"
}

const  = UserForm()

// the original object's age key is now a number
console.log(.age)

onUndeclaredKey

像 TypeScript 一样,ArkType 默认在验证期间忽略未声明的键。然而,它还支持两种额外的行为:

  • "ignore" (默认):允许输入上的未声明键,在输出上保留它们
  • "delete":允许输入上的未声明键,在返回输出之前删除它们
  • "reject":拒绝带有未声明键的输入

这些行为可以通过内置的 "+" 语法与单个 Type 关联(请参阅 那些文档 以了解它们的工作原理)。您也可以全局更改默认值:

config.ts
import { configure } from "arktype/config"

configure({ onUndeclaredKey: "delete" })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

const  = type({
	name: "string"
})

// out is now { name: "Alice" }
const  = UserForm({
	name: "Alice",
	age: "42"
})

exactOptionalPropertyTypes

默认情况下,ArkType 将可选键验证为 TypeScript 的 exactOptionalPropertyTypes 设置为 true

查看示例
const  = ({
	"key?": "number"
})

// valid data
const  = MyObj({})

// Error: key must be a number (was undefined)
const  = MyObj({ key: undefined })

这种方法允许对可选性进行最细粒度的控制,因为可以将 | undefined 添加到应该接受它的属性。

但是,如果您没有启用 TypeScript 的 exactOptionalPropertyTypes 设置,您可以全局将 ArkType 的 exactOptionalPropertyTypes 配置为 false 以匹配 TypeScript 的行为。如果您这样做,我们建议制定计划在未来启用 exactOptionalPropertyTypes

config.ts
import { configure } from "arktype/config"

// since the default in ArkType is `true`, this will only have an effect if set to `false`
configure({ exactOptionalPropertyTypes: false })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

const  = type({
	"key?": "number"
})

// valid data
const  = MyObj({})

// now also valid data (would be an error by default)
const  = MyObj({ key: undefined })

exactOptionalPropertyTypes 尚未影响默认值!

const  = ({
	key: "number = 5"
})

// { key: 5 }
const  = MyObj({})

// { key: undefined }
const  = MyObj({ key: undefined })

对此的支持作为 此更广泛的可配置默认性问题 的一部分进行跟踪。

jitless

默认情况下,当 Type 被实例化时,ArkType 将预编译优化的验证逻辑,该逻辑将在类型被调用时运行。此行为在不支持 new Function 的环境中默认禁用,例如 Cloudflare Workers。

如果您出于其他原因想选择退出,可以将 jitless 配置选项设置为 true

config.ts
import { configure } from "arktype/config"

configure({ jitless: true })
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

// will not be precompiled
const  = type({
	foo: "string"
})

onFail

在某些领域,您可能总是希望在验证失败时抛出错误,或以其他方式转换结果。

通过在全局配置中指定 onFail,您可以控制在无效数据上调用 Type 时会发生什么:

config.ts
import { configure } from "arktype/config"

const  = configure({
	onFail: errors => errors.throw()
})

// be sure to specify both the runtime and static configs

declare global {
	interface ArkEnv {
		onFail: typeof .onFail
	}
}
app.ts
import "./config.ts"
// import your config file before arktype
import { type } from "arktype"

// data is inferred as string- no need to discriminate!
const  = type.string("foo")

// now thrown instead of returned
// ArkErrors: must be a string (was number)
const  = type.string(5)

metadata

还可以将额外的任意元数据与 Type 关联。

甚至可以通过 ArkType 为此目的暴露的接口扩展来使其类型安全:

// add this anywhere in your project
declare global {
	interface ArkEnv {
		meta(): {
			// meta properties should always be optional
			secretIngredient?: string
		}
	}
}

// now types you define can specify and access your metadata
const  = ({
	broth: "'miso' | 'vegetable'",
	ingredients: "string[]"
}).configure({ secretIngredient: "nothing!" })

toJsonSchema

某些 ArkType 功能没有 JSON Schema 等价物。默认情况下,toJsonSchema() 在这些情况下将抛出错误。

此行为可以细粒度配置以匹配您的需求。

const  = ({
	"[symbol]": "string",
	birthday: "Date"
})

const  = .toJsonSchema({
	fallback: {
		// ✅ the "default" key is a fallback for any non-explicitly handled code
		// ✅ ctx includes "base" (represents the schema being generated) and other code-specific props
		// ✅ returning `ctx.base` will effectively ignore the incompatible constraint
		default: ctx => ctx.base,
		// handle specific incompatibilities granularly
		date: ctx => ({
			...ctx.base,
			type: "string",
			format: "date-time",
			description: ctx.after ? `after ${ctx.after}` : "anytime"
		})
	}
})

const  = {
	$schema: "https://json-schema.org/draft/2020-12/schema",
	type: "object",
	properties: {
		// Date instance is now a date-time string as specified by the `date` handler
		birthday: { type: "string", format: "date-time", description: "anytime" }
	},
	required: ["birthday"]
	// symbolic index signature ignored as specified by the `default` handler
}

fallback 配置的根部也可以指定 default 处理程序:

const  = ({
	"[symbol]": "string",
	birthday: "Date"
})

//--- cut ---

const  = .toJsonSchema({
	// "just make it work"
	fallback: ctx => ctx.base
})

这些选项也可以在 全局或 scope 级别 设置。

Fallback Codes

这是 toJsonSchema() 可能失败的可配置原因的完整列表。

Code描述
arrayObject具有对象属性的数组
arrayPostfix具有后缀元素的数组
defaultValue非可序列化的默认值
domain非可序列化的类型关键字(总是 bigintsymbol
morph转换
patternIntersection多个正则约束
predicate自定义窄化函数
proto非可序列化的 instanceof
symbolKey对象上的符号键
unit非可序列化的 === 引用(例如 undefined
dateDate 实例(对于 Date 取代 proto

prototypes

当您 .infer 您的 Type 时,ArkType 会遍历它们并提取像 morphs 这样的特殊值,例如 (In: string) => Out<number>

虽然通常这能够保留原始类型,但它效率低下,并且可能意外扩展某些对象类型。

您可以使用类型级别的 prototypes 配置来告诉 ArkType 将这些类型视为外部:

declare global {
	interface ArkEnv {
		prototypes(): MySpecialClass
	}
}

class MySpecialClass {}

const 
const T: Type<MySpecialClass, {}>
T
= type.instanceOf(MySpecialClass)

On this page