TypeScript泛型都不会,你怎么做前端er!

156 阅读2分钟

TS(TypeScript) 是 JavaScript 的超集,赋能 JS 类型。

  • 代码既文档
  • 编译器自动提示

泛型

首先需要明确一点,用 TS 写不代表 TS 支持友好。

function identity0(arg: any): any {
  return arg;
}

let str0 = identity0("typescript"); // let str0: any
let num0 = identity0(1); // let num0: any

想要实现正确的类型推导,就得使用泛型 👇

// 相当于 type T = arg 的类型
function identity<T>(arg: T): T {
  return arg;
}

let str = identity<string>("typescript"); // let str: string
let num = identity<number>(1); // let num: number

keyof

keyof关键字:拆解已有类型

interface VueCourse5 {
  name: string;
  price: number;
}
type CourseProps = keyof VueCourse5; // 只能是name和price选一个

let k: CourseProps = "name";
let k1: CourseProps = "pric"; // Type '"pric"' is not assignable to type 'keyof VueCourse5'. Did you mean '"price"'?

extends

extends关键字:条件判断

type ExtendsType<T> = T extends boolean ? "重学前端" : "玩转Vue 3";
type ExtendsType1 = ExtendsType<boolean>; // type ExtendsType1='重学前端'
type ExtendsType2 = ExtendsType<string>; // type ExtendsType2='玩转Vue 3'

in

in关键字:循环

type Courses = "VUE" | "JS";
type CourseObj = {
  [k in Courses]: number; // 遍历Courses类型作为key
};
// 上面的代码等于下面的定义
// type CourseObj = {
//     VUE: number;
//     JS: number;
// }

infer

infer关键字:进一步判断

type Foo = () => CourseObj;
// 如果T是一个函数,并且函数返回类型是P就返回P
type ReturnType1<T> = T extends () => infer P ? P : never;
type Foo1 = ReturnType1<Foo>;

实战

看懂 TS 🥳

// K extends keyof T限制K的类型必须是T的属性之一
// T[K]是值的类型
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name];
}
const coursePrice: CourseObj = {
  VUE: 129,
  TS: 129,
};
getProperty(coursePrice, "VUE");
getProperty(coursePrice, "TS");

定义接口

需求:定义 Todo 类型,字段可选。

interface Todo {
  title: string;
  desc: string;
  done: boolean;
}

type Partial1<T> = {
  [K in keyof T]?: T[K];
};
type partTodo = Partial1<Todo>;

Interface API

需求:规范接口,友好提示。

// import axios from "axios";
const axios = {
  post(url, obj) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          return xhr.responseText;
        }
      }
    };
    xhr.send(obj);
  },
};

// 如果 message必传 怎么提醒缺少参数
// 接口不存在 类型需要怎么报错
interface Api {
  "/course/buy": {
    id: number;
  };
  "/course/comment": {
    id: number;
    message: string;
  };
}

function request<T extends keyof Api>(url: T, obj: Api[T]) {
  return axios.post(url, obj);
}

request("/course/buy", { id: 1 });
request("/course/comment", { id: 1, message: 2 }); // Type 'number' is not assignable to type 'string'.
request("/course/comment", { id: 1 }); // Argument of type '{ id: number; }' is not assignable to parameter of type '{ id: number; message: string; }'.
request("/course/404", { id: 1 }); // Argument of type '"/course/404"' is not assignable to parameter of type 'keyof Api'.