quartet
创建用于数据验证的库时,设置了以下标志:
在本文中,我想考虑专注quartet
于TypeScript。
动机
我们使用TypeScript处理我们的项目。因此,当我创建该库时,我希望认识TypeScript的人不要将四重奏作为对他来说完全陌生的东西来学习,而要在该库中识别他已经知道的知识。
用户定义的类型防护
考虑一个例子。我们使用API请求有关用户的数据。我们假定它们是以下类型:
interface User {
id: string;
name: string;
gender: "male" | "female";
age: number;
phoneBook: {
[name: string]: string;
};
}
我想从验证功能中得到什么:
const probablyUser: unkown = { ... }
if (checkUser(probablyUser)) {
console.log(probablyUser.name)
} else {
throw new Error('Probably User has not type User')
}
为了实现此目标,使用了用户定义的类型防护。
也就是说,函数声明应如下所示:
function checkUser(probablyUser: any): probablyUser is User {
}
我们quartet
来创建一个这样的函数:
import { v } from "quartet";
const checkUser = v({
id: v.string,
name: v.string,
gender: ["male", "female"],
age: v.number
phoneBook: {
[v.rest]: v.string,
}
});
编写了这样的代码后,我们得到的功能不是TypeGuard:
chechUser: (value: any) => boolean;
要使其成为TypeGuard,必须声明性地指出此函数将验证哪种类型。这样做是这样的:
const checkUser = v<User>({
});
最终:
chechUser: (value: any) => value is User
关于此项目有两点:
保证
开发人员可以指示电路验证了哪种类型的事实可以引起警告,因为很有可能这样编写:
const checkNumber = v<number>({ name: v.string });
— { name: string }
, , number
.
. ( ) , — "" .
, .
, v
. :
const v: <T>(schema: Schema) => (value: any) => value is T;
.
, TypeGuard .
:
const v: <T = any>(schema: Schema) => (value: any) => value is T;
, — never
:
const checkNumber = v(v.number);
const value: any = "123";
if (!checkNumber(value)) {
}
,
,
.
, T
any
, T === any
, .
- :
const v: <T = any>(
schema: Schema
) => IfAny<T, (value: any) => boolean, (value: any) => value is T>;
type IfAny<T,A,B> =
— , :
T — any
:
type IfAny<T, A, B> = true extends T
? "1" extends T
? 1 extends T
? {} extends T
? (() => void) extends T
? null extends T
? A
: B
: B
: B
: B
: B
: B;
, , : boolean | number | string | object | function | null
any
.
TypeScript
, , TypeScript'a .
@hapi/joi
ajv
, User
.
Text Compare .
quartet
const checkUser = v({
id: v.string,
name: v.string,
gender: ["male", "female"],
age: v.number
phoneBook: {
[v.rest]: v.string,
}
})

- : 24
const schema = j.object({
id: j.string().required(),
name: j.string().required(),
gender: j
.string()
.valid("male", "female")
.required(),
age: j.number().required(),
phoneBook: j.object().pattern(/.*/, j.string())
});

, , 118 .
ajv
const checkUser = a.compile({
type: "object",
required: ["id", "name", "gender", "age", "phoneBook"],
properties: {
id: { type: "string" },
name: { type: "string" },
gender: { type: "string", enum: ["male", "female"] },
phoneBook: {
type: "object",
additionalProperties: {
type: "string"
}
}
}
});

, 146 .
:

TypeScript. , , , .
TypeGuard — , .
TypeScript . — .