TypeScript 基本使用

98 阅读5分钟

TypeScript

what?

TypeScript是微软开发的一个开源的编程语言,通过在JavaScript的基础上添加静态类型定义构建而成。

why?

优点:

  • 程序更加容易理解
    • 明确的变量类型
    • 明确的输入输出类型
  • 丰富的接口提示
  • 更少的错误
    • 编译期间能够发现大部分的错误
    • 杜绝一些比较常见的错误
  • 包容性
    • 完全兼容 javascript
    • 第三方库可以单独编写类型文件
    • 流行项目大都支持 typescript

缺点:

  • 增加了一些学习成本
  • 短期内增加了一些开发成本

how to use?

类型推断

// 未自动声明的,ts 会自动进行推断

let str = "str1"; // 为 str 赋值时,str 被推断为 string 类型
str = "str2";
str = 100; // 不能将类型“number”分配给类型“string”。ts(2322)

let num; // 自动推断 -- any

function sum(a: number, b: number) {
  return a + b; // 自动推断 -- 返回值为 number
}

let arr = [1]; // 自动推断 -- number[]
arr.push("s"); // 类型“string”的参数不能赋给类型“number”的参数。ts(2345)

let arr2 = [1, "s"]; // 自动推断 -- (string | number)[]

// 如果不知道怎么写的,可以写一个列子,看编辑器的类型推断
// 直接鼠标 hover obj
let obj = {
  code: 0,
  message: "0",
  ttl: 1,
};

// 得到类型
interface objInterface {
  code: number;
  message: string;
  ttl: number;
}

常见类型

let a: number = 1;
let b: boolean = true;
let c: string = "c";
let d: null = null;
let e: undefined = undefined;
let f: any; // 任意类型,相当于不进行 typescript 检查
let g: unknown; // 未知类型
let h: number[] = [1, 2, 3]; // 数组:写法 1
let i: Array<number> = [1, 2, 3]; // 数组:写法 2
let j: [number, string] = [1, "a"]; // 元组(Tuple):元组类型允许一个已知元素数量和类型的数组,各项可以不同类型
let k: (number | string)[] = [1, "a", 2, "b"]; // 联合类型数组
let l: () => void = () => {}; // void:函数没有返回值
let m: () => never = () => {
  throw new Error("Error");
}; // never:永远不会到达的值(throw Error,无限循环...)
// 对象类型
let n: { name: string; age: number } = { name: "zs", age: 12 };
let o: { name: string; age?: number } = { name: "ls" };

// 内置对象类型(还有很多)
let p: Function;
let q: Object;

// 值类型
let sex: "nan" | "nv" = "nan";
let sex2: 1 | 0 = 1;

// rest 语法
let r = (...rest: number[]) => {
  return rest.reduce((pre, cur) => pre + cur, 0);
};

枚举

enum Sex {
  Girl,
  Boy,
}

const girl: Sex = Sex.Girl;
const boy: Sex = Sex.Boy;

断言

类型断言

let a: unkown = "abcd";

// 使用 as 类型断言
let s1: string = a as string;
// 使用 <type> 类型断言
let s2: string = <string>a;

非空断言

// 取值 DOM 时,获取元素可能不存在,返回值可能为 null
// 明确 DOM 元素存在时,可以使用类型断言
const el: HTMLElement = document.querySelector("#app") as HTMLElement;

// 或者使用非空断言(末尾添加 !)
const el2: HTMLElement = document.querySelector("#app")!;

type

// type 可以为任意类型取别名
type userType = {
  name: string;
  age: number;
  sex?: number; // 可选属性
  readonly id: string; // 只读属性
};

function addUser(user: userType): void {
  console.log("addUser");
}
function updateUser(user: userType): void {
  console.log("updateUser");
}

联合类型

let un: number | string;
un = 1;
un = "s";

let unArr: (number | string)[] = [];
// 或者 let unArr: Array<number | string>
unArr.push(1);
unArr.push("s");

其他属性

type accountType = {
  account: string;
  password: string;
  [propName: string]: any; // 剩余任何属性都能接受,且不报错
};

class User {
  public name: string; // public:所有地方都可以访问
  age: number; // 默认 public 修饰
  protected money: number; // protected:只能在该类或者子类中访问
  private phoneMsg: string; // private:只能在该类中访问
  readonly id: string; // 只读属性
  
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  info(): string {
    return `${this.name} ${this.age}`;
  }
}

const user1 = new User("zs", 12); // 不按照类型提示会报错

单例模式

class Axios {
  private static instance: Axios | null = null;
  private constructor() {}

  static getInstance(): Axios {
    if (Axios.instance === null) {
      Axios.instance = new Axios();
    }
    return Axios.instance;
  }
}

抽象类

abstract class Animal {
  public abstract name: string;
  abstract move(): void;
}

class Dog extends Animal {
  public name: string;
  move() {}
}

接口

interface Animal {
  name: string;
  move(): void;
}

class Dog implements Animal {
  name: string;
  move() {}
}

泛型

// 方法泛型
function dump<T>(args: T): T {
  return args;
}

let du1 = dump<string>("du1");
let du2 = dump<boolean>(true);

// 类泛型
class Collection<T> {
  public data: T;
  getData(): T {
    return this.data;
  }
}

const col = new Collection<string>();

// 接口泛型
interface UserInterface<T> {
  data: T;
}

type UserType<T> = {
  data: T;
};

泛型 extends

// 不是所有的类型都存在 length 属性
function getLength<T extends { length: number }>(arg: T): number {
  return arg.length;
}

as const

// 将类型转化为值类型

let ac = "ac" as const; // ac 的类型从 string 变为 "ac" 值类型

const arrAs = [1, 2, "3"] as const; // 将 (number|string)[] 变为元组 readonly [1, 2, "3"]

const objAs = {
  name: "zs",
  age: 12,
} as const;
// { name: string; age: number; } 变为 { readonly name: "zs"; readonly age: 12; }

keyof

// 获取类,接口等的 key 的值类型
type Keys = keyof { name: string; age: number };

let v1: Keys = "name";
let v2: Keys = "age";

typeof

// 用来获取变量的类型
let name: string = "zs";
let name2: typeof name = "ls";
let name3: typeof name = 12; // 不能将类型“number”分配给类型“string”。ts(2322)

const per = {
  name: "zs",
  age: 18,
};

const per2: typeof per = {
  name: "ls",
  age: 20,
  // “eat”不在类型“{ name: string; age: number; }”中。ts(2322)
  eat() {
    console.log("eat");
  },
};

in

// 用于遍历接口或联合类型的属性
type USER = { name: string; age: number };

type MEMBER<T> = {
  [K in keyof T]: T[K];
};

const per: MEMBER<USER & { address: string }> = {
  name:'zs',
  age:12,
  address:'sz'
};

extends

// 接口继承
type Person = { name: string };
interface User extends Person {
  age: number;
}

const per: User = { name: "zs", age: 12 };

// 泛型继承
function getLength<T extends { length: number }>(o: T): number {
  return o.length;
}

// 类型条件判断
type Animal = { name: string; age: number };

type Dog = { name: string; age: number; water(): void };

type Flag = Dog extends Animal ? true : false;

const f: Flag = true;
const f2: Flag = false; // 不能将类型“false”分配给类型“true”。ts(2322)

// 联合类型
type S = string;
type SN = string | number;

const r1: S extends SN ? true : false = true;

Exclude

type S = string;
type SN = string | number;

const r: Exclude<SN, S> = 100;
const r2: Exclude<SN, S> = "100"; // 不能将类型“string”分配给类型“number”。ts(2322)

// 实现原理
type EXCLUDE<T, U> = T extends U ? never : T;

Extract

// Extract 和 Exclude 相反,用于获取相交的类型
type SNB = string | number | boolean;
type SN = string | number;
const r1: Extract<SNB, SN> = 12;
const r2: Extract<SNB, SN> = "12";
const r3: Extract<SNB, SN> = true; // 不能将类型“boolean”分配给类型“string | number”。ts(2322)

// 实现原理
type EXTRSCT<T, U> = T extends U ? T : never;

Pick

// 用于挑选属性
type Person = {
  name: string;
  age: number;
  eat(): void;
};
const p: Pick<Person, "name" | "age"> = {
  name: "zs",
  age: 20,
  eat() {}, // “eat”不在类型“Pick<Person, "name" | "age">”中。ts(2322)
};

// 实现原理
type PICK<T, U extends keyof T> = {
  [P in U]: T[P];
};

Omit

// Omit 和 Pick 相反,用来排除指定属性
type Person = {
  name: string;
  age: number;
  eat(): void;
};
const p: Omit<Person, "eat"> = {
  name: "zs",
  age: 20,
  eat() {}, // “eat”不在类型“Omit<Person, "eat">”中。ts(2322)
};

// 实现原理
type Omit<T, U> = Pick<T, Exclude<keyof T, U>>;

Partial

// 用于将全部属性设置为可选的
type Person = {
  name: string;
  age: number;
  eat(): void;
  sleep(): void;
};
const p: Partial<Person> = {
  sleep() {
    console.log("sleep");
  },
};

// 实现原理
type PARTIAL<T> = {
  [P in keyof T]?: T[P];
};

Record

// 用于快速定义对象类型
type Person = Record<"name" | "age", string | number>;
const p: Person = {
  name: "zs" || 12,
  age: 12 || "sd",
};

// 实现原理
type RECORD<K extends string | number | symbol, V> = {
  [P in K]: V;
};