TS|青训营笔记

52 阅读4分钟

“这是我参与「第五届青训营 」笔记创作活动的第4天”

可以参考的学习资料

练习的地方

TS基本语法

/* 字符串 */
const q: string = 'string';
/* 数字 */
const q: number = 0;
/* 布尔值 */
const q: boolean = true;
/* null */
const q: null = null;
/* 字符串 */
const q: undefined = undefined;
复制代码

对基础数据类型来说,我们一般需要给它限制具体的数据类型,这是TS的规范之一。

对象类型

  • 可以自己创建一个自己想要的格式「类型」
const bytedancer: IBytedancer = {
  jobId: 9303245,
  name: 'Lin',
  sex: 'man',
  age: 28,
  hobby: 'swimming',
}
复制代码

一般这个IBytedancer前面有一个I,表示它是我们自定义得出的。

还可以这样定义「使用interface

interface IBytedancer {
  readonly jobId: number;
  name: string;
  sex: 'man'|'woman'|'other';
  age: number;
  hobby?: string;
  [key: string]: any;
}
复制代码
  1. 其中readonly表示这是一个只读属性,如果你后续想要去修改他,会得到报错。
  2. 其中?表示这是一个可选属性,也就是定义该属性可以不存在
  3. 其中:any表示这是一个任意属性,约束所有对象属性都必须是该属性的子类型

函数类型

  • 之前的JS
function add(x, y) {
  return x + y
}
const mult = (x, y) => x * y
复制代码
  • 现在的TS
function add(x: number, y: number): number {
  return x + y;
}
复制代码

给基础数据类型做了一些限制,还有给函数的返回值做了一些限制

const mult: (x: number, y: number) => number = (x, y) => x * y
复制代码

函数重载

function getDate(type: 'string', timestamp?: string): string;
interface IGetDate {
  (type: 'string', timestamp?: string): string;
  (type: 'date', timestamp?: string): Date;
  (type: 'string'|'date',timestamp?:string): Date | string;
}
复制代码

数组类型

  • 「类型 + 方括号」表示
type IArr1 = number[];
复制代码
  • 泛型表示
type IArr2 = Array<string | number | Record<string, number>>;
复制代码
  • 元组表示
type IArr3 = [number, number, string, string]
复制代码
  • 接口表示
interface IArr4 {
  [key: number]: any;
}
复制代码

Typescript补充类型

  • 空类型,表示无赋值
type IEmptyFunction = () => void;
复制代码
  • 任意类型,是所有类型的子类型
type IAnyType = any;
复制代码
  • 枚举类型:支持枚举值到枚举名的正,反向映射「仅有数字可以|字符串不行」
enum EnumExample { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
EnumExample['Mon'] === 0
EnumExample[0] = 'Mon'
复制代码
  • 泛型
type INumArr = Array<number>;
复制代码

Typescript泛型

function getRepeatArr(target) {
  return new Array(100).fill(target);
}

type IGetRepeatArr = (target: any) => any[];
复制代码
  • 不预先指定具体的类型,而在使用的时候再指定类型的一种特性
type IGetRepeatArrR = <T>(target: T) => T[];
复制代码
  • 泛型接口 & 多泛型
interface IX<T, U> {
  key: T;
  val: U;
}
复制代码
  • 泛型类
class IMan<T> {
  instance: T;
}
复制代码
  • 泛型别名
type ITypeArr<T> = Array<T>;
复制代码

泛型约束

这里是通过extends给泛型添加约束的

type IGetRepeatStringArr = <T extends string>(target: T) => T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target)
getStrArr(123) // 会报错!!!因为是number类型的数据
复制代码

类型别名 & 类型断言

  • 通过 type 关键字定义了 IObjArr 的别名。
type IObjArr = Array<{
  key: string;
  [objKey: string]: any;
}>
复制代码
functiom keyBu<T extends IObjArr>(objArr: Array<T>) {
  const result = objArr.reduce((res, val, key) => {
    res[key] = val;
    return res;
  }, {});
  return result as Record<string, T>;
}
复制代码
  • 还可以直接用字面量来定义类型
type IDomTag = 'html' | 'body' | 'div' | 'span'
type IOddNumber = 1 | 2 | 3 | 4 | 5 | 7 | 9
复制代码

联合/交叉类型

  • 联合类型:IAIB;联合类型表示一个值可以是几种类型之一
  • 交叉类型:IA&IB;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
type IBookList = Array<{
  author: string;
} & ({
  type: 'history';
  range: string;
} | {
  type: 'story';
  theme: string
})>
复制代码

类型保护与类型守卫

interface IA {a: 1, a1: 2}
interface IB {b: 1, b1: 2}
function log2(arg: IA | IB) {
  // 这里是会报错的,如果说存在问题的话
  if(arg.a) {
    console.log(arg.a1)
  } else {
    console.log(arg.b1)
  }
}
复制代码
  • 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域
function getIsIA(arg: IA | IB): arg is IA {
  return !!(arg as IA).a;
}
// 再来判断是IA还是IB就不会出问题了
function log3(arg: IA | IB) {
  if (getIsIA(arg)) {
    console.log(arg.a1)
  } else {
    console.log(arg.b1)
  }
}
复制代码

高级类型

/**
 * 实现merge函数类型
 * 要求sourceObj必须为targetObj的子集
 */
function merge1(sourceObj, targetObj) {
  // 扩展运算符拿出来这些东西
  const result = { ...sourceObj };
  for(let key in targetObj) {
    const itemVal = sourceObj[key];
    // 就是替换原本有的东西
    itemVal && (result[key] = itemVal);
  }
  return result;
}
// Question 不太懂这样做了有啥意义
function merge2(sourceObj, targetObj) {
  return { ...sourceObj, ...targetObj };
}
复制代码
  • 类型实现频繁:若obj类型较为复杂,则声明source和target便需要大量重复2遍
  • 容易出错:若target增加/减少key,则需要source联动去除
interface ISourceObj {
  x?: string;
  y?: string;
}
interface ITargetObj {
  x: string;
  y: string;
}
type IMerge = (sourceObj: ISourceObj, targetObj: ITargetObj) => ITargetObj;
复制代码
  • 与泛型结合
interface IMerge {
  <T extends Record<string, any>>(sourceObj: Partial<T>, targetObj: T): T;
}

type IPartial<T extends Record<string, any>> = {
  [P in keyof T]?: T[P];
}

type IKeys = keyof {a: string; b: number} // => type IKeys = "a" | "b"