الرباعية 9: اليجرو TypeScript

عندما quartetتم إنشاء مكتبة للتحقق من صحة البيانات ، تم تعيين المعالم التالية:



في هذه المقالة ، أود التفكير في التركيز quartetعلى TypeScript.


التحفيز


نحن نعمل على مشاريعنا باستخدام TypeScript. لذلك ، عندما أنشأت هذه المكتبة ، أردت من الشخص الذي يعرف TypeScript ألا يتعلم الرباعية كشيء جديد تمامًا بالنسبة له ، ولكن أن يتعرف في هذه المكتبة على ما يعرفه بالفعل.


حراس النوع المعرفة من قبل المستخدم


تأمل في مثال. نطلب بيانات حول المستخدم مع واجهة برمجة التطبيقات. نفترض أنها من النوع التالي:


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

ما أريد الحصول عليه من وظيفة التحقق من الصحة:


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

لتحقيق هذا الهدف ، يتم استخدام حراس النوع المعرفة من قبل المستخدم .


أي ، يجب أن يظهر إعلان الوظيفة على النحو التالي:


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

صورة


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

صورة


, , 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 . — .


All Articles