typescript 聚焦业务开发,试着写一写

1,096 阅读3分钟

wo.png

typescript 在业务的使用,更加聚焦业务开发本身。如:用户登录,数据列表,详情页面,安全信息,分析图表,按照数据类型抽象出来,我们一起试着写一写。假设你已经掌握了类型运算的知识,如果没有,可以看上一篇typescript 深化学习,类型运算的原始动力。让我们开始吧...

原始类型

const isLogin: boolean = false;
const price: number = 1;
const userName: string = "Lucy";
// 唯一标识符
const unique: symbol = Symbol("unique");

对象类型

/**
 * 登录可能分为多种渠道:微信,微博,账号登录,手机登录
 * 为简单起见,只分2种,LoginReqByAccount 或者 LoginReqParamsByOther
 */
type LoginType = "account" | "other";

// 账号方式登录请求参数
interface LoginReqByAccount {
  name: string;
  password: string;
  phone: number;
  // 登录类型
  type: LoginType;
  keepPwd?: boolean;
}

// 其它方式登录的请求参数
interface LoginReqParamsByOther {
  id: number;
  // 签名
  sign: string;
  // 登录类型
  type: LoginType;
}

// 登录的请求参数
type LoginParams = LoginReqByAccount | LoginReqParamsByOther;

// 后台返回的业务数据
type ResBusinessData = {
  userId: number;
  // 用户名
  name: string;
  // 昵称,不一定有,可选
  nickName?: string;
  // 会员级别
  level: number;
  // 其它属性
  [p: string]: unknown;
} | null;

interface LoginResponse {
  code: number;
  // 成功错误信息的描述
  message: string;
  // 业务数据
  data: ResBusinessData;
}

// 分页
interface Pagination<T extends number = number> {
  current: T;
  pageSize: T;
}

// 定义一个状态的map对象,以表示不同状态icon
const StatusMap: Map<number, string> = new Map([
  [0, "info"],
  [1, "success"],
  [2, "warning"],
  [3, "error"],
]);

interface PrivilegeShape<T extends number | boolean> {
  [P: string]: T;
}
// 会员特权
const MemberPrivilege: PrivilegeShape<boolean> = {
  // 折扣
  discount: true,
  // 免运费
  freeShipping: false,
};

列表类型

//  列表项1
interface ListItem1 {
  id: number;
  // 标题
  title: string;
  // 价格
  price: number;
  // 促销
  promotion: boolean;
  // 库存
  stock: number;
  // 描述
  desc: string;
}

//  列表项2
interface ListItem2 {
  id: number;
  // 标题
  title: string;
  desc: string;
  // 其它属性
  others: {
    children: number[];
  };
}

// 列表
let list: (ListItem1 | ListItem2)[] = [];

// 集合
const productionIds: Set<number> = new Set([1, 2, 3, 4]);
const userNames: Set<string> = new Set(["a", "b", "c"]);

interface TreeData {
  id: number;
  parentId: number | null;
  groupId?: number;
  name: string;
  phone: number;
}

type Tree<T extends TreeData> = {
  id: number;
  level: number;
  data: T;
  children?: Tree<T>[];
};

第三方库

@types.png

声明文件从来源上可以分为2种:

  • 一种是自己写的可能放在本地,当然可以以包的形式发布到typescript 声明文件库。

  • 还有一种第三方库的声明文件,typescript 声明文件平台,搜索要安装的声明文件,

    有的包在你安装时,就附带安装声明文件,相对比较贴心。如:axios, 放在 node_modules/axios/index.d.ts 有的要自己单独安装,如:express。

// 请先用命令 npn i axios 或者 yarn add axios
// 以 axios 为例,直接import 需要的类型

import axios, { AxiosRequestConfig } from "axios";

// 请求拦截器
const reqInterceptor = (config: AxiosRequestConfig): AxiosRequestConfig => {
  // 做一些拦截处理
  return config;
};

axios.interceptors.request.use(reqInterceptor);

函数类型


// 获取数据列表
function fetchList<T>(params: { id: number; name: string } & Pagination) {
  return axios.post<{ total: number; data: T[] }>("/list", params);
}

fetchList<{ id: number; [p: string]: unknown }>({
  id: 0,
  name: "",
  current: 1,
  pageSize: 10,
});

type TreeNode = {
  id: number;
  name: string;
  children?: TreeNode[];
};

/**
 *
 * @param list 数组节点
 * @param targetId 查看的id
 * @param stack 追逐位置信息
 */
function getArrayIndex(
  list: TreeNode[],
  targetId: number,
  stack: number[] = []
): number[] {
  list.some((item, idx) => {
    stack.push(idx);
    const found = item.id === targetId;
    if (!found) {
      const { children = [] } = item;
      if (children.length > 0) {
        const len = stack.length;
        getArrayIndex(children, targetId, stack);
        return stack.length > len ? true : (stack.pop(), false);
      } else {
        stack.pop();
      }
    }
    return found;
  });

  return stack;
}

结语

每一个程序都是对数据加工处理,抽象成数据类型声明,可以举一反三,试着写一写。写声明文件是typescipt,完全聚焦类型的一个方式,没有一点业务在里面。那为什么, 我们不试一试呢?

文章中如有错漏,欢迎指正,谢谢。