Cuando quartet
se creó la biblioteca para la validación de datos , se establecieron los siguientes puntos de referencia:
En este artículo, me gustaría considerar quartet
centrarme en TypeScript.
Motivación
Trabajamos en nuestros proyectos usando TypeScript. Por lo tanto, cuando creé esta biblioteca, quería que la persona que conoce TypeScript no aprenda cuarteto como algo completamente nuevo para él, sino que reconozca en esta biblioteca lo que ya sabe.
Protectores de tipo definidos por el usuario
Considera un ejemplo. Solicitamos datos sobre el usuario con la API. Suponemos que son del siguiente tipo:
interface User {
id: string;
name: string;
gender: "male" | "female";
age: number;
phoneBook: {
[name: string]: string;
};
}
Lo que quiero obtener de la función de validación:
const probablyUser: unkown = { ... }
if (checkUser(probablyUser)) {
console.log(probablyUser.name)
} else {
throw new Error('Probably User has not type User')
}
Para lograr este objetivo, se utilizan protectores de tipo definidos por el usuario .
Es decir, la declaración de función debería verse así:
function checkUser(probablyUser: any): probablyUser is User {
}
Usemos quartet
para crear tal función:
import { v } from "quartet";
const checkUser = v({
id: v.string,
name: v.string,
gender: ["male", "female"],
age: v.number
phoneBook: {
[v.rest]: v.string,
}
});
Después de escribir dicho código, obtenemos una función que no es TypeGuard:
chechUser: (value: any) => boolean;
Para que sea TypeGuard es necesario indicar declarativamente qué tipo será validado por esta función. Esto se hace así:
const checkUser = v<User>({
});
Finalmente:
chechUser: (value: any) => value is User
Hay dos puntos con respecto a este artículo:
Garantía
El hecho mismo de que el desarrollador pueda indicar qué tipo es validado por el circuito puede alertar, porque es muy posible escribir así:
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 . — .