Quando a biblioteca para validação de dados quartet
foi criada, os seguintes pontos de referência foram definidos:
Neste artigo, gostaria de considerar o foco quartet
no TypeScript.
Motivação
Trabalhamos em nossos projetos usando o TypeScript. Portanto, quando criei esta biblioteca, queria que a pessoa que conhecia o TypeScript não aprendesse o quarteto como algo completamente novo para ele, mas reconhecesse nessa biblioteca o que ele já sabe.
Protetores de tipo definidos pelo usuário
Considere um exemplo. Solicitamos dados sobre o usuário com a API. Assumimos que eles sejam do seguinte tipo:
interface User {
id: string;
name: string;
gender: "male" | "female";
age: number;
phoneBook: {
[name: string]: string;
};
}
O que eu quero obter da função de validação:
const probablyUser: unkown = { ... }
if (checkUser(probablyUser)) {
console.log(probablyUser.name)
} else {
throw new Error('Probably User has not type User')
}
Para atingir esse objetivo, são utilizadas proteções de tipo definido pelo usuário .
Ou seja, a declaração da função deve ficar assim:
function checkUser(probablyUser: any): probablyUser is User {
}
Vamos usar quartet
para criar essa função:
import { v } from "quartet";
const checkUser = v({
id: v.string,
name: v.string,
gender: ["male", "female"],
age: v.number
phoneBook: {
[v.rest]: v.string,
}
});
Depois de escrever esse código, obtemos uma função que não é TypeGuard:
chechUser: (value: any) => boolean;
Para torná-lo TypeGuard, é necessário indicar declarativamente que tipo será validado por esta função. Isso é feito assim:
const checkUser = v<User>({
});
Eventualmente:
chechUser: (value: any) => value is User
Existem dois pontos em relação a este item:
garantia
O próprio fato de o desenvolvedor poder indicar qual tipo é validado pelo circuito pode alertar, porque é bem possível escrever assim:
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 . — .