# TypeScript 常用类型

# 1. 概述

JS 已有类型:

  • 原始类型: number / string / boolean / null / undefined / symbol
  • 对象类型: object (包括 数组、对象、函数)

TS 新增类型:

  • 联合类型
  • 自定义类型(类型别名)
  • 接口
  • 元组
  • 字面量类型
  • 枚举
  • void
  • any
  • ......

# 2. 类型注解

let age: number = 18

: number 就是类型注解,限制变量的类型,只能给变量赋值该类型的值。

# 3. 原始类型

完全按照 JS 中类型的名称来书写即可:

let age        : number     = 18
let personName : string     = '张三'
let isLoading  : boolean    = false
let obj        : null       = null
let myVar      : undefined  = undefined
let id         : symbol     = Symbol()

# 4. 数组类型

说明:

  • 在 JS 中,只有 object 类型; 在 TS 中,把 object 细化了。

示例:(推荐使用第一种写法)

let num1: number[] = [1, 2, 3]

let num2: Array<number> = [1, 2, 3]

# 5. 联合类型

说明:

  • 由多个类型组成的类型,表示可以是这些类型中的任意一种
  • | 连接多个类型

示例:

let age: number | string;

age = 1;
age = 'a';


let names: (number | string)[];

names = [1, 'a'];

# 5.1. 类型别名

说明:

  • 某个类型多次使用,可以抽取成类型别名,达到复用的目的
  • 使用 type 关键字

示例:

// 定义类型别名
type CustomArray = (number | string)[];

// 使用
let arr: CustomArray = [1, 'a']

# 6. 函数类型

函数的类型实际上是: 函数参数和返回值的类型

有两种指定方式:

  1. 单独指定 参数和返回值 的类型
  2. 同时指定 参数和返回值 的类型

# 6.1. 单独指定

说明:

  • 在 形参 后面添加 参数的类型注解
  • 在 函数小括号 后面添加 返回值的类型注解

示例:

function add(num1: number, num2: number): number {
  return num1 + num2;
}

const sum = function (num1: number, num2: number): number {
  return num1 + num2;
}

const sum2 = (num1: number, num2: number): number  => {
  return num1 + num2;
}

# 6.2. 同时指定

说明:

  • 只适用于 函数表达式

示例:

// 声明时,(以箭头函数形式)指定类型
let sum: (num1: number, num2: number) => number;

// 赋值
sum = (num1, num2) => {
  return num1 + num2;
}

// 声明和赋值也可以写在一起,但不容易区分

# 6.3. 可选参数

说明:

  • 传参时,可传可不传
  • 不能位于必选参数之前

示例:

function test(arg1: number, arg2?: number, arg3?: number): void {
  console.log(arg1, arg2, arg3)
}

test(1)        // 1 undefined undefined
test(1, 2)     // 1 2 undefined
test(1, 2, 3)  // 1 2 3

# 6.4. void 类型

说明:

  • 如果函数没有返回值,则返回值类型为 void

示例:

function greet(name: string): void {
  console.log(`${name}, hello!`);
}

# 7. 对象类型

说明:

  • 描述对象的结构
  • 单行时,用 ; 分隔;多行时,可以省略分号

示例:

let person: {
  // 属性
  name: string;

  // 方法
  sayHi(name: string): void

  sayHello: (name: string) => void // 箭头函数形式
} = {
  name: '张三',

  sayHi(name) {
    console.log(name, 'hi');
  },

  sayHello(name) {
    console.log(name, 'hello');
  }
}

# 7.1. 可选属性

说明:

  • 语法与函数可选参数一致,都使用 ? 来表示

示例:

let student: {
  name: string;
  age?: number;
};

student = { name: '张三' };
student = { name: '张三', age: 18 };

# 8. 接口

说明:

  • 对象类型多次使用,可以抽取成接口(interface),达到复用的目的
  • 使用 interface 关键字定义

示例:

interface IPerson {
  name: string;
  sayHi(): void;
}

let person: IPerson = {
  name: '张三',
  sayHi() {
    console.log(this.name, 'hi');
  }
}

# 8.1. interface vs type

说明:

  • 接口 只能给对象指定类型
  • 类型别名 可以为任意类型指定别名

示例:

type IPerson = {
  name: string;
  sayHi(): void;
}

let student: IPerson = {
  name: '张三',
  sayHi() {
    console.log(this.name, 'hi');
  }
}

type StrNum = string | number;

# 8.2. 继承

说明:

  • 将公共的属性、方法抽离出来,通过继承来实现复用
  • 通过 extends 关键字,子接口拥有父接口所有属性和方法

示例:

interface Point2D {
  x: number;
  y: number;
}

interface Point3D extends Point2D {
  z: number;
}

const p: Point3D = { x: 1, y: 2, z: 3 };

# 9. 元组(tuple)

说明:

  • 特殊的数组
  • 指定元素的个数 以及 每个元素的类型

示例:

let position: [number, number] = [39, 116];

# 10. 类型推论

说明:

  • 在某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型
  • 常见场景:1. 声明变量并立即初始化时; 2. 函数返回值

示例:

/*
  等价: 

    let age: number = 12;
 */
let age = 12;

/*
  等价: 

    function sum(num1: number, num2: number): number {
      return num1 + num2
    }
 */
function sum(num1: number, num2: number) {
  return num1 + num2
}

# 11. 类型断言

说明:

  • 设置更具体的类型(强转为某个类型)
  • 查看 DOM 元素具体的类型:element.__proto__

示例:

// 类型推论是 HTMLElement
let aLink1 = document.getElementById('aLink');

// 断言为(强转为)HTMLAnchorElement
let aLink2 = document.getElementById('aLink') as HTMLAnchorElement;

// 也可以使用 `<>` 语法,但是与 JSX 冲突
let aLink3 = <HTMLAnchorElement> document.getElementById('aLink');

# 12. 字面量类型

说明:

  • JS 中的字面量可以作为类型来使用
  • 字面量类型 通常与 配合联合类型 一起使用,用来表示一组明确的可选值

示例:

// 字面量类型单独使用基本没啥意义
let age: 18 = 18;

let stuName: '张三' = '张三'


// 字面量类型与联合类型一起使用,表示一组明确的可选值
let direction: 'up' | 'down' | 'left' | 'right' = 'up';

function setDirection(direction: 'up' | 'down' | 'left' | 'right') {
  // ...
}
setDirection('up');

# 13. 枚举

说明:

  • 定义这一组命名常量。类型为该枚举的变量,其值可以是这些常量中的一个。
  • 类似于 字面量类型+联合类型,也可以表示一组明确的可选值
  • 通过 enum 关键字定义

示例:

// 定义枚举
enum Direction {
  Up,
  Down,
  Left,
  Right
}

// 使用枚举类型
function setDirection(direction: Direction) {}

// 访问枚举成员
setDirection(Direction.Up);

# 13.1. 数字枚举

说明:

  • 枚举成员是有值的,默认是从 0 开始自增的数值
  • 枚举成员的值是数字的枚举,称为 数字枚举

示例:

// 默认从 0 开始,后面成员的值 = 前面成员的值 + 1
enum Direction1 {
  Up,     // 0
  Down,   // 1
  Left,   // 2
  Right,  // 3
}

// 指定第一个成员为 10
enum Direction2 {
  Up = 10,  // 10
  Down,     // 11
  Left,     // 12
  Right,    // 13
}

// 挨个指定成员的初始值
enum Direction3 {
  Up = 10,    // 10
  Down = 11 , // 11
  Left = 22 , // 22
  Right,      // 23
}

# 13.2. 字符串枚举

说明:

  • 枚举成员的值是字符串,称为 字符串枚举
  • 字符串枚举没有自增长行为,所有成员必须指定初始值

示例:

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

# 13.3. 原理

说明:

  • 一般类型编译为 JS 代码后会被移除
  • 枚举不仅用作类型,还提供值,编译后会额外生成一段 JS 代码
  • 推荐使用 字面量类型+联合类型 的方式,更直观、简洁、高效

示例:

/*
编译为 JS:

  var Direction1;
  (function (Direction1) {
    Direction1["Up"] = "UP";
    Direction1["Down"] = "DOWN";
    Direction1["Left"] = "LEFT";
    Direction1["Right"] = "RIGHT";
  })(Direction1 || (Direction1 = {}));

 */
enum Direction1 {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}


/*
编译为 JS:

  var direction = 'UP';

 */
type Direction2 = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT';
let direction: Direction2 = 'UP';

# 14. any 类型

说明:

  • 当值的类型为 any 时,可以对值进行任意操作,且不会有代码提示。(所以不要使用 any 类型)
  • 隐式 any 类型:1. 声明变量时 不给初始值、类型注解;2. 函数参数不给类型注解

示例:

// 显式设置 any 类型,以下操作都没有提示
let a: any = {};
a.x;
a.y = 10;
a();
const n: number = a;

// 隐式 any 类型,声明变量 不给初始值、类型注解
let b;
b.x;
b.y = 10;
b();

// 隐式 any 类型,函数参数 不给类型注解
function add(num1, num2) {}
add(1, '2');

# 15. typeof

说明:

  • TS 中,typeof 在类型注解中使用,表示引用 变量或属性 的类型
  • 可以用于引用默认参数的类型

示例:

console.log( typeof 'hello' ); // "string"

let person: { name: string, age: number } = { name: '张三', age: 18 };

/* 等价于:
  let p2: { name: string, age: number } = { name: '李四', age: 19 };
 */
let p2: typeof person = { name: '李四', age: 19 };

/* 等价于:
  let p2Name: string = '李四';
 */
let p2Name: typeof person.name = '李四';
本章目录