如今前端工程化开发早已离不开 TypeScript。JavaScript 作为弱类型语言,在大型项目中很容易出现类型混乱、隐性报错、代码可读性低、维护成本高等问题,而 TypeScript 是 JavaScript 的超集,在 JS 基础上增加了强大的强类型系统,从编码阶段就约束数据类型,提前规避线上 bug。

本文结合实战代码案例,系统性梳理 TypeScript 全套核心基础知识点,从基础类型、语法到抽象类、接口、泛型逐一讲解,不管是入门学习还是查漏补缺都非常合适。

一、基础开篇:类型声明 & 类型推断

TypeScript 最核心的能力就是类型约束,而类型声明和类型推断是最基础的两个语法。

1. 类型声明

我们可以主动为变量、函数参数、函数返回值指定明确类型,一旦指定,就只能存储对应类型的数据,赋值其他类型会直接抛出语法警告。

变量类型声明

typescript

运行

// 语法:变量名: 类型
let a: string;   // 只能存储字符串
let b: number;   // 只能存储数字
let c: boolean;  // 只能存储布尔值

a = 'hello';
// a = 100;  // 报错:不能将类型“number”分配给类型“string”

b = 666;
// b = '你好'; // 报错:不能将类型“string”分配给类型“number”

c = true;
// c = 666;   // 报错:不能将类型“number”分配给类型“boolean”
函数类型声明

可以约束函数入参类型返回值类型,同时也会校验参数个数:

typescript

运行

// x、y 必须是数字,函数返回值也必须是数字
function demo(x: number, y: number): number {
  return x + y;
}

demo(100, 200);
// demo(100, '200');  // 报错:参数类型不匹配
// demo(100);         // 报错:参数数量不足
// demo(100,200,300); // 报错:参数数量过多

2. 类型推断

如果我们没有手动指定类型,TypeScript 会自动根据初始值推断出变量类型,推断完成后,变量依然受类型约束:

typescript

运行

let d = -99; // TS自动推断 d: number
// d = false; // 报错:不能将类型“boolean”分配给类型“number”

二、TypeScript 数据类型总览

TypeScript 完全兼容 JavaScript 所有原生类型,同时新增了多款专属类型,还支持自定义类型。

1. JavaScript 原生类型

stringnumberbooleannullundefinedbigintsymbolobject

补充:object 包含数组、函数、Date 等引用类型;日常开发极少使用 Number/String/Boolean 包装构造函数。

2. TypeScript 新增类型

voidneverunknownanyenum(枚举)、tuple(元组)

3. TS 自定义类型

通过 typeinterface 自定义复杂类型,满足业务个性化约束。

基础类型对照表

表格

类型 描述 示例
number 数字类型 1、-33、2.5
string 字符串类型 'hello'、' 你好'
boolean 布尔类型 true、false
字面量 固定唯一值 ' 男 '、100
any 任意类型(关闭类型校验) 任意数据
unknown 安全的任意类型 任意数据
never 无有效值
void 空值 /undefined 无返回值函数
object 非原始引用类型 {name: ' 张三 '}
tuple 定长、定类型数组 [string, number]
enum 枚举类型 状态、选项集合

三、常用内置类型深度解析

这部分是 TS 日常开发使用频率最高的内容,逐个拆解用法、特性和注意事项。

3.1 字面量类型

字面量类型会强制变量只能等于指定的固定值,结合|还能实现联合字面量,常用于限定选项、状态。

typescript

运行

// 1. 基础字面量:只能赋值 "你好"
let a: '你好';
a = '你好';
// a = '欢迎'; // 报错:类型不匹配

// 2. 数字字面量:只能赋值 100
let b: 100;
b = 100;
// b = 200; // 报错

// 3. 联合字面量(常用):性别只能是 男 / 女
let gender: '男' | '女';
gender = '男';
gender = '女';
// gender = '未知'; // 报错

3.2 any 任意类型

any 表示放弃类型检查,变量可以赋值任意类型数据,分为显式 any隐式 any

⚠️ 注意:项目中尽量少用 any,会丧失 TS 类型保护的意义。

typescript

运行

// 显式 any:手动指定类型
let a: any;
a = 100;
a = '你好';
a = false;

// 隐式 any:未指定类型、无初始值,TS自动推断为 any
let b;
b = 100;
b = '你好';

// 特性:any 类型变量可以赋值给任意类型变量
let x: string;
x = a; // 无报错

3.3 unknown 未知类型

unknown 被称为类型安全的 any,同样可以接收任意类型数据,但不会关闭类型校验,是推荐的「未知数据」解决方案。

核心特性:

  1. 可以接收任意类型赋值;
  2. 不能直接赋值给其他明确类型;
  3. 不能直接调用属性 / 方法。

typescript

运行

let a: unknown;
a = 100;
a = '你好';

let x: string;
// x = a; // 报错:不能将 unknown 赋值给 string

// 三种合法赋值方式
// 方式1:类型判断(推荐,类型守卫)
if (typeof a === 'string') {
  x = a;
}

// 方式2:类型断言 写法一
x = a as string;

// 方式3:类型断言 写法二(JSX环境不推荐)
x = <string>a;

// 调用方法限制
let str3: unknown = 'hello';
// str3.toUpperCase(); // 报错:unknown 无法直接调用方法
(str3 as string).toUpperCase(); // 断言后正常使用

3.4 never 类型

never 表示不存在任何有效值undefinednull、0、空字符串都不允许赋值。

使用场景:

  1. 几乎不用 never 定义普通变量(无实际意义);
  2. TS 自动推断逻辑永远走不到的代码块;
  3. 约束抛出异常、死循环的函数返回值。

typescript

运行

// 1. 定义 never 变量:所有赋值都会报错
let a: never;
// a = 1;
// a = undefined;

// 2. 函数抛出异常,返回值指定为 never
function demo(): never {
  throw new Error('程序异常退出');
}

3.5 void 类型

void 表示无返回值,等价于 undefined严格模式下不允许赋值 null,绝大多数场景用于约束函数返回值。

typescript

运行

let a: void = undefined;
// let b: void = null; // 严格模式下报错

// 无返回值函数,推荐使用 void
function demo1(): void {}
function demo2(): void { return; }
function demo3(): void { return undefined; }

// function demo4(): void { return 666; } // 报错:返回值类型不匹配

3.6 object 类型

区分 objectObject,是新手高频踩坑点:

  1. object:代表非原始类型(对象、数组、函数),原始类型(字符串、数字、布尔、null、undefined)均不允许赋值;
  2. Object:代表 Object 包装实例,范围极广,开发中几乎不用。

typescript

运行

let a: object;
// 合法:非原始类型
a = {};
a = [1, 2, 3];
a = function(){};

// 报错:原始类型
// a = 1;
// a = '你好';
// a = null;
实际开发的精准类型写法

日常不会单纯使用 object,而是精准定义对象、数组、函数结构:

typescript

运行

// 1. 定义普通对象(? 代表可选属性)
let person: { name: string; age?: number };
person = { name: '张三', age: 18 };
person = { name: '李四' };

// 2. 允许额外属性的对象
let car: { price: number; color: string; [k: string]: any };
car = { price: 100, color: '红色', brand: '华为' };

// 3. 定义数组
let arr1: string[]; // 等价于 Array<string>
arr1 = ['a', 'b', 'c'];

// 4. 定义函数类型
let fn: (a: number, b: number) => number;
fn = (x, y) => x + y;

3.7 tuple 元组

元组(tuple)是固定长度、固定位置类型的特殊数组,区别于普通数组,对每一个位置的类型都有严格约束。

typescript

运行

// 规定:数组第1项为字符串,第2项为数字,长度必须为2
let t: [string, number];
t = ['hello', 123];

// t = ['hello', 123, false]; // 报错:长度超出限制
// t = [123, 'hello'];        // 报错:位置类型不匹配

3.8 enum 枚举

枚举(enum)用于定义一组固定的常量集合,常用于状态、选项、标识等场景,默认从 0 开始自增。

typescript

运行

// 1. 默认枚举:值从 0 开始递增
enum Color {
  Red,    // 0
  Blue,   // 1
  Black   // 2
}
console.log(Color.Red);  // 0
console.log(Color[0]);  // Red

// 2. 自定义初始值,后续自动递增
enum Color2 {
  Red = 6,  // 6
  Blue,     // 7
  Black     // 8
}

// 3. 枚举实战:约束对象属性
let phone: { name: string; price: number; color: Color };
phone = { name: '华为', price: 6500, color: Color.Red };

// 枚举判断
if (phone.color === Color.Red) {
  console.log('手机为红色');
}

四、自定义类型 type

使用 type 可以给复杂类型起别名,灵活组合字面量、枚举、对象等类型,实现高度自定义约束。

typescript

运行

// 1. 用字面量联合定义年级类型
type Grade = 1 | 2 | 3;

// 2. 枚举定义性别
enum Gender {
  Male,
  Female
}

// 3. 组合成学生自定义类型
type Student = {
  name: string;
  age: number;
  gender: Gender;
  grade: Grade;
};

// 使用自定义类型
let s1: Student;
s1 = { name: '张三', age: 18, gender: Gender.Male, grade: 1 };

五、抽象类

抽象类用 abstract 修饰,核心特性:

  1. 不能被实例化,只能被子类继承;
  2. 可以包含普通属性、普通方法、抽象方法(无具体实现);
  3. 子类继承后,必须实现父类的所有抽象方法。

typescript

运行

// 定义抽象类
abstract class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  // 抽象方法:只有声明,没有实现
  abstract speak(): void;

  // 普通方法
  walk() {
    console.log('正在行走');
  }
}

// 子类继承抽象类(extends)
class Teacher extends Person {
  constructor(name: string, age: number) {
    super(name, age); // 调用父类构造器
  }

  // 必须实现抽象方法
  speak() {
    console.log(`我是老师:${this.name}`);
  }
}

// const p = new Person('张三', 18); // 报错:抽象类无法实例化
const t = new Teacher('李老师', 40);
t.speak();

六、接口 Interface

接口(interface)是 TS 核心语法之一,主要用于约束对象结构、类的属性与方法

6.1 基础用法:类实现接口

类通过 implements 关键字实现接口,必须补齐接口中所有属性和方法:

typescript

运行

// 定义接口
interface Person {
  name: string;
  age: number;
  speak(): void;
}

// 类实现接口
class Teacher implements Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  speak() {
    console.log(`我是${this.name}`);
  }
}

6.2 接口特性:可重复声明并自动合并

同一个接口可以多次声明,TS 会自动将所有声明的属性、方法合并:

typescript

运行

interface PersonInter {
  name: string;
  age: number;
}

// 重复声明,自动合并
interface PersonInter {
  speak(): void;
}

// 最终接口包含 name、age、speak
class Student implements PersonInter {
  name: string;
  age: number;
  speak() {}
}

6.3 接口 vs 自定义类型 type

两者都可以定义对象类型,核心区别:

  1. 接口:支持重复声明合并、可以约束类结构(implements),优先用于描述对象 / 类结构
  2. type:单纯的类型别名,不支持重复合并,支持联合类型、交叉类型,灵活度更高。

6.4 接口 vs 抽象类

表格

对比项 抽象类 接口
关键字 extends 继承 implements 实现
方法 可包含普通方法 + 抽象方法 仅能声明抽象方法(无实现)
构造器 可以拥有构造器 不允许拥有构造器

七、属性修饰符

TS 为类的属性提供了 4 种修饰符,控制属性的访问权限和特性:

表格

修饰符 作用 访问范围
readonly 只读属性 仅可读,无法修改
public 公开属性(默认) 类内部、子类、实例都可访问修改
protected 受保护属性 类内部、子类可访问,实例无法访问
private 私有属性 仅当前类内部可访问

typescript

运行

class User {
  public name: string;
  private id: string;
  protected age: number;
  readonly sex: string = '男';

  constructor(name: string, id: string, age: number) {
    this.name = name;
    this.id = id;
    this.age = age;
  }
}

const u = new User('张三', '001', 18);
console.log(u.name);
// console.log(u.id);    // 报错:私有属性
// console.log(u.age);   // 报错:受保护属性
// u.sex = '女';         // 报错:只读属性不可修改

八、泛型(TS 核心难点)

泛型用来解决类型不确定的问题:定义函数 / 类时,无法提前确定数据类型,使用泛型可以实现类型复用、类型约束,大幅提升代码通用性。

8.1 基础泛型函数

<T> 定义泛型占位符(T 是自定义名称,常用 T/K/V):

typescript

运行

// T 代表任意类型,入参和返回值类型保持一致
function test<T>(arg: T): T {
  return arg;
}

test(10);          // TS自动推断 T = number
test<string>('hi'); // 手动指定泛型类型

8.2 多泛型参数

支持同时定义多个泛型:

typescript

运行

function test<T, K>(a: T, b: K): K {
  return b;
}
test<number, string>(10, 'hello');

8.3 类中的泛型

泛型同样可以作用于类,约束类的属性、方法类型:

typescript

运行

class MyClass<T> {
  prop: T;
  constructor(prop: T) {
    this.prop = prop;
  }
}

const c1 = new MyClass<number>(100);

8.4 泛型约束

通过 extends 限制泛型的范围,要求泛型必须满足指定结构:

typescript

运行

// 定义接口:必须包含 length 属性
interface Demo {
  length: number;
}

// 约束 T 必须实现 Demo 接口(拥有 length)
function getLength<T extends Demo>(arg: T): number {
  return arg.length;
}

getLength('123'); // 字符串有 length,合法
getLength({ length: 10 }); // 对象有 length,合法
// getLength(10); // 报错:number 没有 length 属性

九、总结

本文完整梳理了 TypeScript 从基础类型、语法抽象类、接口、泛型的全套核心知识点,覆盖了日常业务开发 90% 以上的 TS 用法:

  1. 基础部分重点掌握类型声明、类型推断、八大内置类型,分清 any/unknownobject/ 元组 / 枚举的区别;
  2. 进阶部分理解 type 自定义类型、抽象类、接口的使用场景与差异;
  3. 难点部分吃透泛型和属性修饰符,泛型是 TS 实现高阶复用的关键。

TypeScript 的学习离不开实战练习,掌握以上知识点后,可以结合 Vue、React 等前端框架进行项目实操,进一步巩固类型思维,彻底发挥 TS 的强类型优势。

更多推荐