指南

类型系统基础

了解 TypeScript 的基本类型、数组与元组、特殊类型、类型注解与推断,以及类型别名和接口的基础知识。

🎯 引言

学会这篇文章,你将能掌握 TypeScript 的核心类型系统基础,能够用类型来描述数据结构,写出更安全、更可维护的代码。了解基本类型、数组和元组、特殊类型及类型注解等,对于前端开发中使用 TypeScript 提升代码质量大有帮助。


🟢 基本类型:string、number、boolean、null、undefined

TypeScript 里最基础的类型就是 JavaScript 中常见的几种类型。它们都是用来描述变量存储的数据的“形状”。

const myName: string = '小明';
const age: number = 25;
const isStudent: boolean = true;

const emptyValue: null = null;
const notAssigned: undefined = undefined;
  • string 用来表示文本,比如名字、地址等。
  • number 表示数字,既可以是整数,也可以是浮点数。
  • boolean 是布尔值,只有两个状态:true 或 false。
  • nullundefined 是两个特殊的值,null 表示“空”,undefined 表示“未定义”。
注意,nullundefined 是不同的类型,尽管值看起来相似。TypeScript 中默认情况下,null 和 undefined 只能赋值给它们各自的类型。

如何理解 null 和 undefined 呢?可以把 null 想象成“空盒子”,里面没有东西,而 undefined 是“盒子还没放东西”。


🟠 数组与元组

数组是存储一组相同类型元素的集合。元组是固定长度、每个元素类型可以不同的数组。

// 数组:存储一组数字
const scores: number[] = [98, 87, 92];

// 也可以用泛型写法
const names: Array<string> = ['小红', '小明', '小刚'];

// 元组:长度固定,每个位置类型不同
const user: [string, number] = ['小明', 25];

数组很直观,就是一列同类型数据。元组更适合描述“记录”,比如用户信息第一项是名字字符串,第二项是年龄数字。

元组的长度和类型顺序是固定的,访问时可以通过索引直接获得对应类型的值。

🔵 any、unknown、void、never

这几个类型是 TypeScript 里比较特殊的类型。

let anything: any = 123;
anything = '变成字符串了';
anything = true; // any 允许赋值任何类型

let notSure: unknown = 10;
notSure = 'hello'; // unknown 也可以赋任何值,但不能随意操作

function sayHello(): void {
    console.log('Hello');
}

function throwError(): never {
    throw new Error('出错了!');
}
  • any 表示“任何类型”,关闭了类型检查,有点像放弃类型安全。建议少用。
  • unknown 表示“未知类型”,相比 any 更安全,使用前需要做类型检查。
  • void 通常用作函数没有返回值时的返回类型。
  • never 表示永远不会有返回值的类型,常用于抛出异常或死循环。
使用 any 类型会破坏 TypeScript 的类型安全,只有在极特殊情况下才推荐使用。

生活中的比喻是,any 就像是一张白纸,你可以画任何东西;unknown 是一张盖着的纸,你得先掀开看清楚才能操作。


⚙️ 函数参数与返回值类型

在前端开发中,函数是核心组成部分。给函数参数和返回值标注类型,可以让代码更严谨,减少运行时错误。

function add(x: number, y: number): number {
    return x + y;
}

这个例子中,函数 add 的参数 xy 都是 number 类型,返回值也是 number。当你调用时传入非数字类型,编译器会报错。

给函数添加类型定义,不仅能帮你避免传错参数,还能让编辑器自动提示参数类型,提升开发效率。

🟣 类型注解 vs 类型推断

TypeScript 的强大之处之一是它会自动推断变量的类型,但你也可以手动写类型注解。

// 类型注解:明确说明类型
const count: number = 10;

// 类型推断:没有写注解,TS 自动推断类型
const message = '你好,TS'; // 自动推断为 string

// 函数参数类型注解
function sum(a: number, b: number): number {
    return a + b;
}
  • 类型注解是显式告诉编译器变量是什么类型。
  • 类型推断是编译器通过变量的初始值自动判断类型。
强烈推荐利用类型推断减少代码冗余,同时在有歧义或复杂数据时使用类型注解提高代码可读性。

举个例子,TypeScript 就像你的贴心助理,帮你猜测变量是什么类型,但当猜不准时,你要告诉它准确信息。


🟤 类型别名(type)与接口(interface)基础介绍

什么是类型别名(Type Alias)?

类型别名使用 type 关键字来为一个类型起一个名字。可以是基本类型、联合类型、元组、对象等。

type UserID = string;

type User = {
    id: UserID;
    name: string;
    age?: number;
};

什么是接口(Interface)?

接口是 TypeScript 提供的一种用于定义对象结构的方式,特别适合面向对象编程中的接口定义。使用 interface 关键字。

interface User {
    id: string;
    name: string;
    age?: number;
}

接口也支持继承和合并,非常适合扩展型的结构设计。

场景 1:定义对象结构 interface 更合适

interface User {
    id: number;
    name: string;
    age?: number;
}

为什么用 interface

  • 更直观地表达“这是一个对象结构”;
  • 支持继承、合并;
  • 更适合被他人扩展,尤其是在写库或声明文件时。

场景 2:定义联合类型必须用 type

type Status = 'loading' | 'success' | 'error';

为什么用 type

  • interface 不能用于联合类型;
  • type 能描述字符串字面量的组合、可选值等。

场景 3:定义元组必须用 type

type Point = [number, number];

为什么用 type

  • 只有 type 可以定义元组 [x, y]
  • interface 不能直接表达这种有序固定长度的数组结构。

场景 5:需要扩展或合并多个结构必须用 interface

interface Animal {
    name: string;
}

interface Dog extends Animal {
    breed: string;
}

或者声明合并:

interface User {
    id: number;
}
interface User {
    name: string;
}
// 合并后等同于:{ id: number; name: string }

type 不能这么做(重复声明会报错)。

什么是枚举(enum)?

枚举(enum)是一种特殊的类型,用来定义一组命名的常量。它能帮你把一堆相关的值统一管理,代码也更清晰。枚举主要分为三种类型。

数字枚举(Numeric Enums)

数字枚举是最常见的形式,枚举成员会自动从 0 开始编号,也可以手动指定初始值,后面的成员依次递增。

enum Direction {
    Up, // 0
    Down, // 1
    Left, // 2
    Right, // 3
}

console.log(Direction.Left); // 2

字符串枚举(String Enums)

字符串枚举的值必须显式赋值,因为它不会自动递增。字符串枚举更适合那些你希望值和名字保持一一对应,且能直接阅读的场景。

enum Role {
    Admin = 'ADMIN',
    User = 'USER',
    Guest = 'GUEST',
}

异构枚举(Heterogeneous Enums,数字和字符串混合)

异构枚举同时包含数字和字符串类型的成员,一般不推荐使用,因为会降低代码的统一性和可读性。

enum Result {
    Success = 1,
    Fail = 'FAIL',
}
小提示:枚举会在编译后生成对应的代码哦!

🧾 小节总结

  • TypeScript 基本类型包括 string、number、boolean、null、undefined,都是描述变量基本数据形态。
  • 数组用来存储同类型集合,元组是长度固定、类型不同的数组。
  • 特殊类型 any 表示任意类型但不安全,unknown 更安全,void 代表无返回值,never 代表永远不返回。
  • 类型注解显式声明类型,类型推断自动推断,合理搭配提升代码安全易读。
  • 类型别名和接口都是给复杂类型起名字,但接口支持继承和实现,更适合面向对象设计。

❓ 知识问答(Q&A)

Q:TypeScript 中,anyunknown 有什么区别?

A:any 关闭类型检查,可以随意操作;unknown 更安全,使用前必须先做类型检查。

Q:什么情况下适合用元组而不是数组?

A:当数据长度固定且每个位置类型不同,比如用户信息时,适合用元组。

Q:接口和类型别名的主要区别是什么?

A:接口支持继承和实现,适合面向对象设计;类型别名更灵活,能定义联合类型等。


🧪 小练习

练习 1:写一个类型别名,表示一个商品对象,包含名字(字符串)、价格(数字)、是否有库存(布尔)。

type Product = {
    // 在这里写你的代码
};

const phone: Product = {
    // 在这里初始化 phone 对象
};

练习 2:写一个函数,接受一个元组类型参数,表示人的名字和年龄,函数返回字符串介绍该人。

function introduce(person: [string, number]): string {
    // 在这里写你的代码
}

console.log(introduce(['小明', 25])); // 输出示例:我是小明,今年25岁。

🎉 恭喜你已经掌握 TypeScript 的基本类型、数组与元组、特殊类型、类型注解与推断,以及类型别名和接口基础技能啦!继续练习,提升你的前端开发能力吧!