中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Typescript怎么使用裝飾器實現接口字段映射與Mock

發布時間:2023-04-15 11:10:21 來源:億速云 閱讀:234 作者:iii 欄目:開發技術

本篇內容主要講解“Typescript怎么使用裝飾器實現接口字段映射與Mock”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Typescript怎么使用裝飾器實現接口字段映射與Mock”吧!

需求

最核心的問題就是要達到:接口字段的修改不能影響項目中實際使用的字段,無論是字段名的修改還是類型的修改

這里考慮使用裝飾器附帶額外信息,主要是接口字段信息,與需要轉換的類型

既然可以轉換類型了,考慮把字段 “翻譯” 功能加上

既然能轉換了,能就再加個 Mock 吧,擺脫開發過程中對后端接口的依賴

設計

語言:typescript 構建工具:rollup 自動化測試:jest 代碼規范:eslint + prettier 提交規范:commitlint

Decorator

首先,我們需要一個對象

是這個對象 {}

class Lesson {
  public name: string;
  public teacher: string;
  public datetime: string;
  public applicants: number;
  public compulsory: boolean;
  constructor() {
    this.name = "";
    this.teacher = "";
    this.datetime = "";
    this.compulsory = false;
  }
}

上面的代碼,就是我們構造出的 Lesson 類,它的屬性字段就是我們會在項目中實際使用的字段

現在我們需要把這個類的屬性字段與接口返回的字段對應上,這時候就需要用到 裝飾器 了,隨便取個名字,我這里是用 mapperProperty,接收兩個參數,第一個是接口返回的字段名,第二個是期望最終得到的類型(不是接口字段本身的類型)

class Lesson {
  @mapperProperty("ClassName", "string")
  public name: string;
  @mapperProperty("TeacherName", "string")
  public teacher: string;
  @mapperProperty("DateTime", "datetime")
  public datetime: string;
  @mapperProperty("ApplicantNumber", "int")
  public applicants: number;
  @mapperProperty("Compulsory", "boolean")
  public compulsory: boolean;
  constructor() {
    this.name = "";
    this.teacher = "";
    this.datetime = "";
    this.date = "";
    this.time = "";
    this.compulsory = false;
  }
}

如上面的代碼,我們給每個屬性字段都加上了裝飾器,并告知了接口中對應的字段名稱,以及我們希望得到的類型。 例如代碼中的 applicants 字段,對應了接口中的 ApplicantNumber 字段,無論接口返回的是字符串還是數值類型,我們都希望最終得到的是 int 類型(指代整數)的數據

接下來要把接口字段名稱與我們期望得到的類型先緩存起來

這里我們借助 Reflect Metadata 實現緩存

示例代碼如下

function mapperProperty(apiField, type) {
  Reflect.metadata("key", {
    apiField, // 接口字段名
    type, // 期望類型
  });
}

Reflect Metadata 是 ES7 的一個提案,它主要用來在聲明的時候添加和讀取元數據;我們使用 reflect-metadata 來模擬該功能

Transform

有了接口字段名與期望的類型,接下來的轉換就簡單了

第一步,先讀取上一步緩存的元數據信息

const instance = new Lesson();
const meta = Reflect.getMetadata("key", instance, "applicants");
console.log(meta);

這里的 key 即元數據的鍵,上面的代碼是讀取 Lesson 類中 applicants 字段的元數據,meta 打印的結果如下

{
    apiField: 'ApplicantNumber',
    type: 'int'
}

第二步,轉換

function deserialize(clazz, json) {
  const instance = new clazz();
  const meta = Reflect.getMetadata("key", instance, "applicants");
  const { apiField, type } = meta;
  const ori = json[apiField]; // json 為接口返回的數據
  let value;
  switch (type) {
    case "int":
      value = parseInt(ori, 10);
      break;
    // 其它類型轉換
  }
  // 后續處理
}

到這基本就實現了最核心的能力,只要愿意可以擴展更多類型,歡迎一起來完善

Object and Array

對象與數組的轉換與基本類型的轉換大差不差,這里我將對象、數組的裝飾器命名為 deepMapperProperty,只需將第二個參數的類型,改為接收一個類即可

示例代碼如下

function deepMapperProperty(apiField, clazz) {
  Reflect.metadata("key", {
    apiField, // 接口字段名
    clazz, // 子級
  });
}

取值方式同上,不再贅述了,只需改一下轉換的代碼

轉換對象的示例代碼如下,遞歸調用一下即可

const { clazz } = meta;
if (clazz) {
  value = deserialize(clazz, value);
}

數組則直接使用 map 遍歷

function deserializeArr(clazz, list) {
  return list.map((ele) => deserialize(clazz, ele));
}

Mock

模擬數據部分,是直接返回的前端項目中使用的字段,而非修改接口字段的返回值

實現模擬數據攏共分三步:

與轉換同樣的步驟,要先讀取字段的期望類型,這里只需要類型即可

遍歷讀取類中各個字段的元數據,得到各個字段的期望類型

根據期望類型使用不同的隨機函數,生成相應類型的數據,這里我封裝了三種類型的隨機函數

  • 獲取隨機整數

  • 獲取隨機字符串

  • 獲取隨機小數

針對對象與數組特殊處理

  • 對象:這個簡單,老規矩,遞歸解決

  • 數組:數組需要先隨機生成一下數組長度,再使用 map 遍歷,遞歸調用一下 mock 函數

使用

安裝

npm i type-json-mapper

屬性裝飾器

內置三種類屬性裝飾器:

@mapperProperty(apiField, type)

基本數據類型使用該裝飾器

接收兩個參數:

  • apiField:接口字段名

  • type:字段轉換類型(可選值:string | int | flot | boolean | date | time | datetime)

@deepMapperProperty (apiField, Class)

對象/數組使用該裝飾器

接收兩個參數:

  • apiField:接口字段名

  • Class:類

@filterMapperProperty(apiField, filterFunc)

自定義過濾器(翻譯)使用該裝飾器

接收兩個參數:

  • apiField:接口字段名

  • filterFunc:自定義過濾器函數

const filterFunc = (value) => {
  return "translated text";
};

方法

deserialize(Clazz, json)

反序列化 json 對象

  • Clazz:類

  • json:接口返回的對象數據

deserializeArr(Clazz, list)

反序列化數組

  • Clazz:類

  • list:接口返回的數組數據

mock(Clazz, option)

生成模擬數據

  • Clazz:類

  • option:mock 配置

mock 配置

名稱類型描述默認值
fieldLengthObject字段長度-
arrayFieldsstring[]數組類型字段-

fieldLength

數據類型length 含義
string字符串長度
int最大整數
float字符長度(保留兩位小數)

例:

class Student {
  @mapperProperty("StudentID", "string")
  public id: string;
  @mapperProperty("StudentName", "string")
  public name: string;
  @mapperProperty("StudentAge", "int")
  public age: number;
  @mapperProperty("Grade", "float")
  public grade: number;
  constructor() {
    this.id = "";
    this.name = "";
    this.age = 0;
    this.grade = 0;
  }
}
mock(Student, { fieldLength: { age: 20, grade: 4, name: 6 } });
/**
 * age: 20 表示隨機生成的 age 字段的范圍在 1 ~ 20 之間
 * grade: 4 表述隨機生成的 grade 字段是兩位整數加兩位小數的形式,共4個數字字符(如:23.33)
 * name: 6 表述將隨機生成長度為 6 的隨機字符串
 */

使用示例

這里預先造了幾個類,并給類屬性加上了裝飾器

import {
  mapperProperty,
  deepMapperProperty,
  filterMapperProperty,
} from "type-json-mapper";
class Lesson {
  @mapperProperty("ClassName", "string")
  public name: string;
  @mapperProperty("Teacher", "string")
  public teacher: string;
  @mapperProperty("DateTime", "datetime")
  public datetime: string;
  @mapperProperty("Date", "date")
  public date: string;
  @mapperProperty("Time", "time")
  public time: string;
  @mapperProperty("Compulsory", "boolean")
  public compulsory: boolean;
  constructor() {
    this.name = "";
    this.teacher = "";
    this.datetime = "";
    this.date = "";
    this.time = "";
    this.compulsory = false;
  }
}
class Address {
  @mapperProperty("province", "string")
  public province: string;
  @mapperProperty("city", "string")
  public city: string;
  @mapperProperty("full_address", "string")
  public fullAddress: string;
  constructor() {
    this.province = "";
    this.city = "";
    this.fullAddress = "";
  }
}
// 狀態映射關系
const stateMap = { "1": "讀書中", "2": "輟學", "3": "畢業" };
class Student {
  @mapperProperty("StudentID", "string")
  public id: string;
  @mapperProperty("StudentName", "string")
  public name: string;
  @mapperProperty("StudentAge", "int")
  public age: number;
  @mapperProperty("StudentSex", "string")
  public sex: string;
  @mapperProperty("Grade", "float")
  public grade: number;
  @deepMapperProperty("Address", Address)
  public address?: Address;
  @deepMapperProperty("Lessons", Lesson)
  public lessons?: Lesson[];
  @filterMapperProperty("State", (val: number) => stateMap[`${val}`])
  public status: string;
  @filterMapperProperty("Position", (val: number) => stateMap[`${val}`])
  public position: string;
  public extra: string;
  constructor() {
    this.id = "";
    this.name = "";
    this.age = 0;
    this.sex = "";
    this.grade = 0;
    this.address = undefined;
    this.lessons = undefined;
    this.status = "";
    this.position = "";
    this.extra = "";
  }
}

以下是接口返回的數據:

const json = [
  {
    StudentID: "123456",
    StudentName: "李子明",
    StudentAge: "10",
    StudentSex: 1,
    Grade: "98.6",
    Address: {
      province: "廣東",
      city: "深圳",
      full_address: "xxx小學三年二班",
    },
    Lessons: [
      {
        ClassName: "中國上下五千年",
        Teacher: "建國老師",
        DateTime: 1609430399000,
        Date: 1609430399000,
        Time: 1609430399000,
        Compulsory: 1,
      },
      {
        ClassName: "古箏的魅力",
        Teacher: "美麗老師",
        DateTime: "",
      },
    ],
    State: 1,
    Position: 123,
    extra: "額外信息",
  },
  {
    StudentID: "888888",
    StudentName: "丁儀",
    StudentAge: "18",
    StudentSex: 2,
    Grade: null,
    Address: {
      province: "浙江",
      city: "杭州",
      full_address: "xxx中學高三二班",
    },
    Lessons: [],
    State: 2,
  },
];

開始轉換,因接口返回的是數組,這里使用 deserializeArr

import { deserializeArr } from "type-json-mapper";
try {
  const [first, second] = deserializeArr(Student, json);
  console.log(first);
  console.log(second);
} catch (err) {
  console.error(err);
}

輸出結果如下

// first
{
  id: "123456",
  name: "李子明",
  age: 10,
  sex: "1",
  grade: 98.6,
  address: { province: "廣東", city: "深圳", fullAddress: "xxx小學三 年二班" },
  lessons: [
    {
      name: "中國上下五千年",
      teacher: "建國老師",
      datetime: "2020-12-31 23:59:59",
      date: "2020-12-31",
      time: "23:59:59",
      compulsory: true,
    },
    {
      name: "古箏的魅力",
      teacher: "美麗老師",
      datetime: "",
      date: undefined,
      time: undefined,
      compulsory: undefined,
    },
  ],
  status: "讀書中",
  position: 123,
  extra: "額外信息",
};
// second
{
  id: "888888",
  name: "丁儀",
  age: 18,
  sex: "2",
  grade: null,
  address: { province: "浙江", city: "杭州", fullAddress: "xxx中學高三二班" },
  lessons: [],
  status: "輟學",
  position: undefined,
  extra: undefined,
};

如果后端接口還沒開發完成,我們還可以直接 mock

import { mock } from "type-json-mapper";
const res = mock(Student, {
  fieldLength: { age: 20, grade: 4, name: 6 },
  arrayFields: ["lessons"],
});
console.log(res);

輸出結果如下

{
  id: 'QGBLBA',  name: 'KTFH6d',
  age: 4,
  sex: 'IINfTm',
  grade: 76.15,
  address: { province: 'qvbCte', city: 'DbHfFZ', fullAddress: 'BQ4uIL' },
  lessons: [
    {
      name: 'JDtNMx',
      teacher: 'AeI6hB',
      datetime: '2023-2-18 15:00:07',
      date: '2023-2-18',
      time: '15:00:07',
      compulsory: true
    },
    {
      name: 'BIggA8',
      teacher: '8byaId',
      datetime: '2023-2-18 15:00:07',
      date: '2023-2-18',
      time: '15:00:07',
      compulsory: false
    },
    {
      name: 'pVda1n',
      teacher: 'BPCmwa',
      datetime: '2023-2-18 15:00:07',
      date: '2023-2-18',
      time: '15:00:07',
      compulsory: false
    }
  ],
  status: '',
  position: '',
  extra: ''
}

到此,相信大家對“Typescript怎么使用裝飾器實現接口字段映射與Mock”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凌海市| 丹凤县| 安塞县| 林甸县| 于都县| 星子县| 郎溪县| 固安县| 通辽市| 安顺市| 绥芬河市| 兴化市| 鹿邑县| 黑龙江省| 新干县| 岗巴县| 泗洪县| 柳江县| 辽宁省| 招远市| 岑溪市| 普洱| 东阳市| 鄂州市| 汕尾市| 黄龙县| 甘泉县| 华坪县| 当雄县| 巴南区| 万源市| 城固县| 县级市| 南宁市| 新郑市| 长治县| 中卫市| 淄博市| 西城区| 大埔县| 阿荣旗|