Skip to content

数据类型与类型注解、推断

上节偏 有哪些类型,下节偏 如何写类型与推断规则


第一部分:数据类型

基础类型:string、number、boolean、null、undefined、symbol

对象类型:Array、object

独有类型:enum、元组(tuple)

安全类型:any、unknown、void、never

合成类型:联合类型、交叉类型

高级类型:类型别名、字面量类型、接口类型

基础类型

  1. string 类型
ts
let str: string = 'hello world';
  1. number 类型
ts
// number 类型包括整数、浮点数、NaN、Infinity

let num: number = 123;
  1. boolean 类型
ts
let bool: boolean = true;
  1. undefined 类型
ts
// 1. 在关闭 strictNullChecks(不推荐)时,undefined 可视为广泛可赋值;开启 strictNullChecks(`strict` 默认包含)后,undefined 不能随意赋给 string 等类型,需写成联合类型
let und: undefined = undefined;

// 2. 单独定义没什么用,一般用于联合类型,让数据兼容 undefined 类型
let strOrUnd: string | undefined;
strOrUnd = undefined;
strOrUnd = 'abc';
  1. null 类型
ts
// 与 undefined 类似:是否可隐式赋给其它类型取决于 strictNullChecks
let nul: null = null;

// 单独定义没什么用,一般用于联合类型,让数据兼容 null 类型
let strOrNul: string | null;
strOrNul = null;
strOrNul = 'abc';
  1. Symbol 类型
js
let sym: symbol = Symbol("key");

对象类型

  1. object 类型
ts
// 表示非原始类型(即不是 number、string、boolean 等)
let obj: object = { name: 'Alice' };
obj = []; // 数组也是对象,所以可以赋值
// obj = 1; // 报错:数字是原始类型,不能赋值给 object 类型
  1. 数组类型
ts
// 有两种定义方式
let list1: number[] = [1, 2, 3]; // 方式一
let list2: Array<number> = [1, 2, 3]; // 方式二(泛型写法)

// 多维数组
let list3: string[][] = [
  ['a', 'b', 'c'],
  ['e', 'f', 'g'],
];

独有类型

  1. 枚举类型 enum
ts
enum Color {
  Red,
  Green,
  Blue,
}
let c: Color = Color.Green; // 默认下标从 0 开始,Green 的值是 1

// 也可以手动赋值
enum Status {
  Success = 1,
  Fail = 0,
}
  1. 元组类型 Tuple
ts
// 固定长度和类型的数组

// 声明一个元组,第一个元素是 string,第二个是 number
let x: [string, number];
x = ['hello', 10]; // 正确
// x = [10, "hello"]; // 报错:顺序必须匹配
// x = ["hello", 10, false]; // 报错:长度超过 2

安全类型

  1. any 任意类型(关闭类型检查)
    • any 与大多数类型互相赋值时都会绕过严格校验(尽量少用,以免失去 TS 保护)。
    • 常见于迁移旧 JS、与动态数据临时对接等场景。
ts
let notSure: any = 4;
notSure = 'maybe a string'; // 可以
notSure = false; // 可以
// 使用场景:当正在迁移 JS 代码,或者确实无法预知类型时
  1. unknown 未知类型(类型安全的 any,使用时收窄类型)
    • unknown 是顶层类型:任意类型的值都可赋给 unknown;把 unknown 赋给其它类型前必须先收窄(或通过断言,断言仍有风险)。
ts
let notSure: unknown = 4;
notSure = 'maybe a string'; // 可以

// 与 any 的区别:unknown 不能直接赋值给其他变量,也不能直接调用方法
let a: any = notSure; // any 可以接收 unknown
let b: string = notSure; // 报错:不能将 unknown 赋值给 string

// unknown 类型的变量使用前必须进行类型检查
if (typeof notSure === 'string') {
  let b: string = notSure; // 检查后可以赋值
}
  1. void 表示没有任何类型(用在函数没有返回值时)
ts
// 显式定义无返回值函数
function say(msg: string): void {
  console.log(msg);
}

// 隐式定义无返回值函数,TS 会自动推断类型,无返回值的情况下默认为 void
function sayDefault(msg: string) {
  console.log(msg);
}
  1. never 从不会出现的值 (用在函数中,当函数抛出异常或者无限循环的时候的返回值)
    • 从不会出现的值:当一个函数抛出异常或者无法执行到终止点时,它的返回值为 never 类型
    • 其他类型的数据不能赋值给 never 类型数据(除了 never 类型数据)
ts
// 1. 函数总是抛出异常,无法返回
function error(message: string): never {
  throw new Error(message);
}

// 2. 函数存在无限循环,永远无法执行完
function infiniteLoop(): never {
  while (true) {}
}

合成类型

  1. 联合类型(兼容不同类型)—— 或
js
let id: number | string;
id = 10; // 正确
id = "abc"; // 正确
// id = false; // 报错
  1. 交叉类型(扩展额外类型)—— 与
js
interface Person { name: string; }
interface Contact { email: string; }
type Employee = Person & Contact; // Employee 必须同时具备 name 和 email

let e: Employee = { name: "Tom", email: "tom@example.com" };

高级类型

  1. 类型别名
js
type Name = string;
type NameResolver = () => string;

// 常用于联合类型
type ID = number | string;
  1. 字面量类型
js
// 字符串字面量
let direction: "up" | "down";
direction = "up"; // 正确
// direction = "left"; // 报错

// 数字字面量
let num: 1 | 2 | 3;
num = 2; // 正确
  1. 接口类型
JS
// 定义接口
interface IUser {
  id: number;
  name: string;
  email?: string; // 可选属性
}

// 使用接口
const user: IUser = {
  id: 1,
  name: 'Alice'
};

注意

重点掌握 interface(接口)和 type(类型别名)的组合用法,因为在实际项目中,90% 的类型定义都是由它们组合基础类型完成的


第二部分:类型注解与推断

类型注解

当不确定变量的类型时,需要显式的给变量定义类型(当类型推断无法推断出变量类型时,才使用类型注解)

类型推断

定义有初始值变量时,无需指定变量的类型,TS 会自动推断出类型 (推断的类型为赋值的数据类型)

ts
// 无初始值变量:需要指定类型(即:类型注解)
let str: string;
str = "edf";

// 有初始值变量:不需要指定类型,TS 会自动进行推导出类型,推导结果为:let num: number;(即:类型推断)
let num = 100;
num = 99;