TypeScript 从零基础到精通(二):基础类型与类型系统

TypeScript 从零基础到精通(二):基础类型与类型系统 摘要类型是 TypeScript 的核心。本文从最基础的类型number、string、boolean讲起逐步深入到数组、元组、枚举、any、unknown、void、null/undefined、never 等类型。你还会学到类型注解、类型推导、联合类型、字面量类型等实用概念。一、前言在上一篇中我们已经搭建好了 TypeScript 环境并写了一个简单的sayHello函数初步体验了类型检查的魅力。今天我们将系统学习 TypeScript 的所有基础类型。掌握了这些你就能给绝大多数的 JavaScript 代码加上准确的类型注解让编辑器为你保驾护航。二、类型注解Type Annotation与类型推导Type Inference2.1 类型注解类型注解就是手动给变量、参数、返回值指定类型。语法是在标识符后面加上: 类型。// 变量注解 let age: number 25; let name: string 小明; let isStudent: boolean true; // 参数和返回值注解 function multiply(x: number, y: number): number { return x * y; }如果不小心赋错类型TypeScript 会立刻报错age 二十五; // ❌ 类型“string”不能赋值给类型“number”2.2 类型推导TypeScript 非常智能如果你没有写类型注解它会根据初始值自动推导出类型。let message Hello; // 推导为 string 类型 message 42; // ❌ 不能将 number 赋给 string这种自动推导极大减少了我们写类型的工作量。推荐的实践是简单变量让 TS 推导函数参数和返回值显式注解。三、原始类型number、string、boolean这三种类型对应 JavaScript 的原始值。3.1 number包括整数、浮点数、负数、NaN、Infinity 等。let intNum: number 42; let floatNum: number 3.14; let negative: number -10; let notANumber: number NaN; let infinity: number Infinity;3.2 string可以使用单引号、双引号或模板字符串。let single: string Hello; let double: string World; let template: string Hello, ${single} ${double}!;3.3 boolean只有true和false。let isDone: boolean false; let isGreater: boolean 10 5; // true小贴士在 TypeScript 中number、string、boolean都是小写不要写成大写Number、String、Boolean它们是 JavaScript 的包装对象类型几乎用不到。四、数组与元组4.1 数组有两种写法// 方式一类型后加 [] let list1: number[] [1, 2, 3]; ​ // 方式二泛型 Array类型 let list2: Arraystring [a, b, c];如果数组中既有数字又有字符串可以用联合类型后面会讲或者any[]不推荐。4.2 元组Tuple元组是固定长度、每个位置类型已知的数组。这是 JavaScript 没有的概念。let person: [string, number] [张三, 25]; // 第一个必须是 string第二个必须是 number ​ // 可以单独访问 let name person[0]; // string 类型 let age person[1]; // number 类型 ​ // 越界访问会报错 person[2] extra; // ❌ 长度为 2 的元组不能添加元素元组常用于表示一对值比如键值对、坐标、函数返回值等。五、枚举enum让代码更语义化枚举用来定义一组命名常量。在 JavaScript 中没有原生枚举TS 提供了enum关键字。5.1 数字枚举enum Direction { Up, // 默认值 0 Down, // 1 Left, // 2 Right // 3 } ​ let move: Direction Direction.Up; console.log(move); // 输出 0 console.log(Direction[0]); // 输出 Up反向映射你也可以手动赋值enum StatusCode { OK 200, NotFound 404, InternalError 500 }5.2 字符串枚举enum Color { Red RED, Green GREEN, Blue BLUE }字符串枚举不能反向映射但可读性更好。5.3 枚举的使用场景比如表示一周的天数、订单状态、用户角色等。enum UserRole { Admin admin, Editor editor, Viewer viewer } ​ function checkPermission(role: UserRole) { if (role UserRole.Admin) { console.log(拥有所有权限); } }注意枚举编译后会生成一个 JavaScript 对象会稍微增加代码体积。对于简单场景也可以使用联合类型替代后面会提到。六、any、unknown、void、null / undefined、never这五种类型是 TS 中的特殊类型各有用途。6.1 any —— 关闭类型检查当你暂时不知道类型或者想迁就旧 JS 代码时可以用any。一旦使用了anyTS 就不再对该变量做任何检查。let notSure: any 4; notSure 字符串; // 可以 notSure true; // 可以 notSure.toFixed(); // 运行时可能出错但 TS 不会阻止缺点any会破坏 TS 的保护建议尽量少用。如果要表示“类型未知”更推荐使用unknown。6.2 unknown —— 安全的 anyunknown表示“我还不确定是什么类型”你不能直接使用它的属性或方法必须先收窄类型。let value: unknown Hello; ​ // ❌ 报错value 可能是其他类型不能直接调用字符串方法 // console.log(value.toUpperCase()); ​ // 正确做法类型收窄 if (typeof value string) { console.log(value.toUpperCase()); // 现在安全了 }unknown比any更安全推荐用于处理动态内容如 API 响应。6.3 void —— 没有返回值用于函数没有返回值时。实际上void表示函数返回undefined或null。function logMessage(msg: string): void { console.log(msg); // 没有 return或者 return; / return undefined; }变量也可以声明为void类型但只能赋undefined或null如果strictNullChecks关闭实际很少这样用。6.4 null 和 undefined在 TypeScript 中null和undefined既是值也是类型。let u: undefined undefined; let n: null null;默认情况下null和undefined可以赋值给任何其他类型例如let num: number undefined这很容易引发问题。所以强烈建议在tsconfig.json中开启strictNullChecks: true这样它们就只能赋值给自身或void。// tsconfig.json { compilerOptions: { strictNullChecks: true } }开启后let age: number undefined; // ❌ 不能将 undefined 赋给 number6.5 never —— 永远不会发生的类型never表示函数永远不会正常返回比如抛出异常或无限循环或者一个永远不可能有值的变量。// 抛出错误的函数返回值类型是 never function throwError(message: string): never { throw new Error(message); } ​ // 无限循环 function infiniteLoop(): never { while (true) {} }never是所有类型的子类型可以赋值给任何类型但没有类型是never的子类型除了never自身。七、联合类型Union Types与类型收窄7.1 联合类型一个变量可能拥有多种类型之一用竖线|分隔。let id: string | number; id abc123; // 合法 id 10086; // 合法 id true; // ❌ 不能是 boolean函数参数也常用联合类型function formatValue(value: string | number): string { // 类型收窄前不能直接调用字符串或数字特有方法 if (typeof value string) { return value.toUpperCase(); } else { return value.toFixed(2); } }7.2 类型收窄Type Narrowing当使用联合类型时TS 需要你通过某些方式缩窄具体类型才能安全地操作。常用方法typeof类型守卫Array.isArray()in操作符自定义类型守卫后续文章会讲function printLength(input: string | string[]) { if (typeof input string) { console.log(input.length); // ✅ 此时 input 为 string } else { console.log(input.length); // ✅ 此时 input 为 string[] } }八、字面量类型字面量类型是指一个具体的值作为类型。例如hello可以作为类型这意味着这个变量只能赋值为hello。let greeting: hello hello; greeting world; // ❌ 不能将 world 赋给类型 hello字面量类型通常与联合类型结合模拟枚举效果type Direction up | down | left | right; let move: Direction up; // 合法 move north; // ❌ 不在联合中这种“字符串字面量联合类型”比enum更轻量编译后不产生额外代码在 TS 社区很流行。还可以有数字字面量类型和布尔字面量类型let dice: 1 | 2 | 3 | 4 | 5 | 6 4; let isTrue: true true;九、类型别名type当同一个联合类型或复杂类型在多处使用时可以用type给它起个名字。// 定义别名 type UserID string | number; type Status pending | success | error; ​ function handleUser(id: UserID, status: Status) { // ... }类型别名还可以用于对象类型类似接口后面会详细讲type Point { x: number; y: number; }; ​ let p: Point { x: 10, y: 20 };提示type和interface有很多重叠但各有侧重。简单的对象和联合类型用type需要继承或实现的用interface。十、总结TypeScript 的类型系统是结构化的鸭子类型只要结构匹配即可不需要显式声明继承关系。开启strictNullChecks能避免大量 null/undefined 引发的错误。优先使用类型推导但函数参数和返回值建议显式注解。any是逃生舱尽量用unknown代替。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。动手练习是掌握编程最快的方法请务必亲手敲一遍本文的所有示例代码并截图保存你的成果。你的关注是我坚持原创和细节共享的力量来源谢谢大家。