Kuartet 9: Allegro | TypeScript

Saat pustaka untuk validasi data quartetdibuat, landmark berikut ini ditetapkan:



Pada artikel ini, saya ingin mempertimbangkan fokus quartetpada TypeScript.


Motivasi


Kami mengerjakan proyek kami menggunakan TypeScript. Oleh karena itu, ketika saya membuat perpustakaan ini, saya ingin orang yang tahu TypeScript tidak belajar kuartet sebagai sesuatu yang sama sekali baru baginya, tetapi untuk belajar di perpustakaan ini apa yang sudah dia ketahui.


Pelindung Tipe Yang Ditentukan Pengguna


Pertimbangkan sebuah contoh. Kami meminta data tentang pengguna dengan API. Kami berasumsi bahwa mereka adalah dari jenis berikut:


interface User {
  id: string;
  name: string;
  gender: "male" | "female";
  age: number;
  phoneBook: {
    [name: string]: string;
  };
}

Yang ingin saya dapatkan dari fungsi validasi:


const probablyUser: unkown = { ... }

if (checkUser(probablyUser)) {
    // probablyUser has type User
    console.log(probablyUser.name)
} else {
    // probablyUser has type unkown
    throw new Error('Probably User has not type User')
}

Untuk mencapai tujuan ini, Penjaga Tipe Buatan Pengguna digunakan .


Artinya, deklarasi fungsi akan terlihat seperti ini:


function checkUser(probablyUser: any): probablyUser is User {
  // ...
}

Mari kita gunakan quartetuntuk membuat fungsi seperti itu:


import { v } from "quartet";

const checkUser = v({
  id: v.string,
  name: v.string,
  gender: ["male", "female"],
  age: v.number
  phoneBook: {
    [v.rest]: v.string,
  }
});

Setelah menulis kode seperti itu, kita mendapatkan fungsi yang bukan TypeGuard:


chechUser: (value: any) => boolean;

Untuk membuatnya TypeGuard perlu menunjukkan secara deklaratif jenis mana yang akan divalidasi oleh fungsi ini. Ini dilakukan seperti ini:


const checkUser = v<User>({
  // ...
});

Akhirnya:


chechUser: (value: any) => value is User

Ada dua poin mengenai item ini:


Jaminan


Fakta bahwa pengembang dapat menunjukkan tipe mana yang divalidasi oleh rangkaian dapat mengingatkan, karena sangat mungkin untuk menulis seperti ini:


const checkNumber = v<number>({ name: v.string });
// checkNumber: (value: any) => value is number

{ 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)) {
  // value has type never
}

, , .


, 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,
  }
})

gambar


- : 24


hapi/joi


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())
});

gambar


, , 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"
      }
    }
  }
});

gambar


, 146 .


:


gambar


TypeScript. , , , .



TypeGuard — , .


TypeScript . — .


All Articles