CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
TypeScript 核心/课时/基本类型
RawBlame
课时目录12 节

TypeScript 核心

  1. 01TypeScript 是什么
  2. 02基本类型
  3. 03函数类型
  4. 04接口与类型别名
  5. 05联合与交叉类型
  6. 06类型收窄
  7. 07泛型
  8. 08工具类型
  9. 09模块与 tsconfig
  10. 10React 组件 typing
  11. 11异步与 API 类型
  12. 12综合练习与 Next.js

基本类型

原始类型、数组、tuple、any/unknown 区别。

30 分钟

基本类型

这一课你将能做到

  1. 给变量正确标注 string / number / boolean / 数组 / 元组 / 枚举
  2. 说清楚 any / unknown / never / void 四个特殊类型各自的用途和使用时机
  3. 理解字面量类型与类型推断,知道什么时候该写注解、什么时候让 TS 自己推

为什么要学

类型系统是 TypeScript 的全部地基,而基本类型是地基里的第一层砖。后面要学的接口、泛型、工具类型,全都是在这些基础类型之上做组合。

更重要的是避坑:初学者最容易栽在三个地方——把 any 当万能钥匙、分不清 null/undefined 和 never、不知道数组的 number[] 和 Array<number> 是同一个东西。这一课一次性讲透。

先建立图像

TS 基本类型的家族树:

原始类型:string  number  boolean  null  undefined  symbol  bigint
特殊类型:any  unknown  never  void
复合类型:数组 T[]  元组 [T1, T2]  枚举 enum  字面量类型 "a" | 1 | true
对象类型:object / interface / type(下一课详讲)

记忆口诀:

  • any = 放弃治疗(什么都能装,装完随便用)
  • unknown = 安全的不确定(什么都能装,用之前必须验明正身)
  • never = 永远不可能(函数永远回不来、穷尽检查兜底)
  • void = 没返回值(函数只干活不交货)

跟着做

新建 types-demo.ts,所有代码都可以直接 tsc types-demo.ts && node types-demo.js 运行。

步骤 1:三种原始类型

let username: string = "小明";
let age: number = 25;
let isMember: boolean = true;

// 模板字符串也是 string
let intro: string = `${username} 今年 ${age} 岁`;

console.log(intro); // 小明 今年 25 岁

注意:TS 里 number 不区分整数浮点数,25 和 25.5 都是 number。

步骤 2:类型推断——大多数时候不用写注解

let city = "北京";        // TS 自动推断为 string
let score = 99.5;         // 自动推断为 number

// city = 123;            // 报错:Type 'number' is not assignable to type 'string'

原则:变量初始化时 TS 能推出来的,就别手写。注解主要用在「推不出来」的地方:函数参数、空数组、初始为 null 的变量。

步骤 3:数组与元组

// 数组:所有元素同类型
let tags: string[] = ["前端", "TS", "React"];
let scores: number[] = [90, 85, 77];
let flags: Array<boolean> = [true, false]; // 泛型写法,等价于 boolean[]

tags.push("全栈");
// tags.push(1); // 报错

// 元组:固定长度、每个位置类型固定
let user: [string, number] = ["小明", 25];
console.log(user[0].toUpperCase()); // 第一个位置是 string,有 string 的方法
// let bad: [string, number] = [25, "小明"]; // 报错:顺序错了

数组 vs 元组:数组是「任意长度、同一类型」,元组是「固定长度、各位置类型可不同」。React 的 useState 返回值就是元组:[状态, 设置函数]。

步骤 4:枚举 enum

enum Status {
  Draft,      // 0
  Published,  // 1
  Archived,   // 2
}

let articleStatus: Status = Status.Published;
console.log(articleStatus);       // 1
console.log(Status[1]);           // "Published"(反向映射)

// 字符串枚举(实际项目更常用,日志可读)
enum Role {
  Admin = "ADMIN",
  Editor = "EDITOR",
  Viewer = "VIEWER",
}

let myRole: Role = Role.Admin;

什么时候用枚举:一组固定的、穷尽的取值,比如订单状态、用户角色。如果取值是开放的字符串,用字面量联合(后面讲)更合适。

步骤 5:any、unknown、never、void 四连

// any:放弃检查(能不用就不用)
let flexible: any = "hello";
flexible = 123;
flexible.foo.bar; // 编译不报错,运行时炸

// unknown:安全的不确定
let input: unknown = JSON.parse('"hello"');
// input.toUpperCase(); // 报错:必须先收窄
if (typeof input === "string") {
  console.log(input.toUpperCase()); // OK:HELLO
}

// void:函数没有返回值
function logMessage(msg: string): void {
  console.log(msg);
  // 没有 return,或 return; 空返回
}

// never:永远不会有结果
function throwError(message: string): never {
  throw new Error(message); // 抛异常,函数永远走不到结尾
}

function infiniteLoop(): never {
  while (true) {} // 死循环,也回不来
}

步骤 6:null、undefined 与字面量类型

// strictNullChecks 开启时(strict 模式默认开)
let name: string = "张三";
// name = null; // 报错!string 不包含 null

let nickname: string | null = null; // 显式允许 null
nickname = "小张";

// 字面量类型:值本身就是类型
let direction: "up" | "down" | "left" | "right";
direction = "up";
// direction = "forward"; // 报错:不在字面量列表里

let version: 1 | 2 | 3 = 2;

| null 和字面量联合是日常写得最多的类型组合,务必练熟。

步骤 7:完整可运行示例

enum Level {
  Beginner = "BEGINNER",
  Advanced = "ADVANCED",
}

function formatStudent(name: string, age: number, level: Level): string {
  const tag: string = level === Level.Beginner ? "初学者" : "进阶者";
  return `${name}(${age} 岁,${tag})`;
}

const students: string[] = [
  formatStudent("小明", 20, Level.Beginner),
  formatStudent("小红", 28, Level.Advanced),
];

for (const s of students) {
  console.log(s);
}
// 输出:
// 小明(20 岁,初学者)
// 小红(28 岁,进阶者)

讲清楚要点

  1. 优先靠推断,其次写注解:let x = 1 不用写 : number。注解的主战场是函数签名和空值初始化。
  2. unknown 是 any 的安全替代:任何值都能赋给 unknown,但使用它之前必须用 typeof 等手段收窄,编译器强制你验货。
  3. never 表示「不可能到达」:抛出异常的函数、死循环函数返回 never;它还用于联合类型的穷尽检查(后面类型收窄课详讲)。
  4. void vs undefined:void 是函数返回类型,表示「不关心返回值」;undefined 是一个具体的值。写函数返回类型用 void。
  5. 元组是定长异构数组:[string, number] 长度必须为 2,位置类型固定。解构赋值时配合极佳。
  6. strict 模式下 null 不再隐身:string 类型装不下 null,必须写成 string | null,这能拦住线上最多的「读 null 的属性」事故。

你可能会懵的地方

  • number[] 和 Array<number> 有区别吗? 没有,完全等价。短类型用 number[],复杂嵌套如 Array<string | number> 用泛型写法更清晰。

  • 枚举编译后是什么样? 数字枚举会编译成一个带双向映射的对象(Status[0] = "Draft" 且 Status["Draft"] = 0)。字符串枚举只有正向映射。担心体积可以用 const enum 或字面量联合替代。

  • 为什么 let a = null 推断出来不是 null 类型? strict 模式下,let a = null 推断为 any(历史包袱),const a = null 才推断为字面量 null。所以初始为空的变量要手写注解:let a: string | null = null。

  • 元组能用 push 加元素吗? 类型层面不允许越界,但 push 一个符合位置类型的元素编译器有时放行——这是 TS 已知的局限性,靠团队约定别这么干。

  • object 类型有什么用? 表示「非原始类型」,但太宽泛(数组、函数、对象都算),实际开发中几乎不用,都是用 interface 精确描述形状。

错法对照

错法问题正解
拿不准就标 any类型检查失效,错误延迟到运行时用 unknown + 收窄,或定义精确类型
function f(): undefinedundefined 不是「无返回」的写法无返回写 void
let arr = [] 之后 arr.push(1)空数组推断为 any[](隐式 any)初始化时标注:let arr: number[] = []
用魔法数字判断状态 if (s === 1)可读性差、易写错用枚举 Status.Published 或字面量联合
let x: string = nullstrict 模式报错需要可空就写 string | null

卡点急救

  1. 报错 Type 'null' is not assignable to type 'string':strict 模式在工作。要么改类型为 string | null,要么赋值前判空。
  2. 空数组 push 报错 implicitly has type 'any[]':声明时给类型:const list: string[] = []。
  3. 枚举值打印出来是数字:数字枚举本来就这样,日志要可读请改用字符串枚举。
  4. JSON.parse 结果是 any:TS 4.x 起 JSON.parse 返回 any,手动转 unknown 再收窄,避免类型污染扩散。

面试常问

  • any 和 unknown 的区别? 赋值层面一样(什么都能装),使用层面相反:any 可以任意操作不报错;unknown 必须先类型收窄才能操作。unknown 是类型安全的 any。

  • never 类型有什么实际用途? 两个:一是永远抛错或死循环的函数返回值;二是 switch 穷尽检查——把 never 赋给未处理的联合分支,新增类型时编译器会提醒你补 case。

  • null 和 undefined 在 TS 里的区别? undefined 表示「声明了没赋值 / 参数没传 / 属性不存在」;null 表示「显式的空」。strict 模式下两者都是独立类型,不能随意赋给其他类型。TS 官方风格指南建议统一用 undefined。

  • 什么时候用元组而不是数组? 当结构固定、位置有意义时:如坐标 [number, number]、键值对 [string, number]、React useState 的返回值。元素同构且数量不定就用数组。

自测三问

  1. function f(): never 和 function f(): void 分别描述什么样的函数?
  2. let a = [] 在 strict 模式下有什么问题?怎么写才对?
  3. 后端返回的 JSON 数据应该标成 any 还是 unknown?为什么?

小结一句话

基本类型是 TS 的字母表:原始类型管值,数组元组管集合,枚举管固定取值,any/unknown/never/void 管四种特殊情况——用对了,类型系统才开始为你干活。

延伸

  • Handbook: Everyday Types
  • 下一课:函数类型——参数、返回值、可选参数、默认参数、剩余参数、函数重载。
加载本节练习…
← 上一课TypeScript 是什么下一课 →函数类型