第三章:基本类型
本章概述
TypeScript 拥有丰富的类型系统,本章将深入讲解基本数据类型,包括原始类型、数组、元组等。理解这些基础类型是掌握 TypeScript 类型系统的关键。
3.1 原始类型(Primitive Types)
3.1.1 boolean 布尔类型
布尔类型只有两种值:true 和 false。
```typescript
let isDone: boolean = false;
let isActive: boolean = true;
let hasPermission: boolean = true;
通过表达式赋值
let isGreater: boolean = 5 > 3; true
let isEqual: boolean = “hello” === “world”; false
布尔对象(不推荐)
let boolObject: Boolean = new Boolean(true); 包装对象
let boolPrimitive: boolean = true; 原始类型,推荐
```
3.1.2 number 数字类型
TypeScript 中所有数字都是浮点数,支持十进制、十六进制、二进制和八进制字面量。
```typescript
十进制
let decimal: number = 42;
let float: number = 3.14159;
let negative: number = -10;
十六进制
let hex: number = 0xff; 255
let hex2: number = 0xABC; 2748
二进制
let binary: number = 0b1010; 10
let binary2: number = 0b11110000;
八进制
let octal: number = 0o744; 484
特殊数值
let infinity: number = Infinity;
let notANumber: number = NaN;
科学计数法
let scientific: number = 1.5e10; 15000000000
let small: number = 1.5e-10;
下划线分隔符(ES2021+)
let million: number = 1_000_000;
let binaryWithSep: number = 0b1111_0000;
```
3.1.3 string 字符串类型
```typescript
单引号
let singleQuote: string = 'Hello';
双引号
let doubleQuote: string = “World”;
模板字符串(推荐)
let name: string = “Alice”;
let greeting: string = `Hello, ${name}!`;
let multiLine: string = `
This is a
multi-line string
`;
模板字符串支持表达式
let a: number = 5;
let b: number = 10;
let result: string = `The sum is ${a + b}`;
字符串方法
let str: string = “TypeScript”;
let upper: string = str.toUpperCase(); “TYPESCRIPT”
let lower: string = str.toLowerCase(); “typescript”
let length: number = str.length; 10
let substring: string = str.substring(0, 4); “Type”
let includes: boolean = str.includes(“Script”); true
```
3.1.4 symbol 符号类型
Symbol 是 ES6 引入的原始数据类型,表示唯一的标识符。
```typescript
创建 Symbol
const sym1: symbol = Symbol();
const sym2: symbol = Symbol(“description”);
const sym3: symbol = Symbol(“description”);
每个 Symbol 都是唯一的
console.log(sym2 === sym3); false
作为对象属性键
const id: symbol = Symbol(“id”);
const user = {
[id]: 12345,
name: "Alice"
};
获取 Symbol 属性需要使用 Object.getOwnPropertySymbols
console.log(Object.getOwnPropertySymbols(user)); [Symbol(id)]
Well-known Symbols
const iterator: symbol = Symbol.iterator;
const asyncIterator: symbol = Symbol.asyncIterator;
const hasInstance: symbol = Symbol.hasInstance;
```
==== 3.1.5 bigint 大整数类型 ====
BigInt 用于表示任意精度的整数,适合处理超出 number 安全整数范围的数值。
```typescript
创建 BigInt
const big1: bigint = 9007199254740991n;
const big2: bigint = BigInt(9007199254740991);
const big3: bigint = BigInt(“900719925474099199999”);
运算
const sum: bigint = big1 + big2;
const product: bigint = big1 * 2n;
const power: bigint = 2n 100n;
比较
const isEqual: boolean = big1 === big2;
const isGreater: boolean = big1 > 0n;
注意:BigInt 和 number 不能直接混合运算
const invalid = big1 + 5; Error
const valid = big1 + 5n; OK
转换
const numFromBig: number = Number(big1); 可能丢失精度
const strFromBig: string = big1.toString();
```
===== 3.2 特殊类型 =====
==== 3.2.1 any 任意类型 ====
any 是最灵活的类型,可以赋值为任何类型,绕过类型检查。
```typescript
let notSure: any = 4;
notSure = “maybe a string instead”;
notSure = false;
notSure = { name: “Alice” };
notSure = [1, 2, 3];
可以访问任何属性
notSure.ifItExists();
notSure.toFixed();
隐式 any
在 noImplicitAny 关闭时,未注解的变量默认为 any
function log(message) { 参数类型隐式为 any
console.log(message);
}
明确的 any 使用场景
1. 第三方库没有类型定义
let thirdPartyData: any = fetchLegacyData();
2. 动态内容
let dynamicContent: any = JSON.parse(jsonString);
3. 逐步迁移项目
可以先用 any,再逐步添加类型
```
==== 3.2.2 unknown 未知类型 ====
unknown 是类型安全的 any,使用前必须进行类型检查。
```typescript
let notSure: unknown = 4;
notSure = “hello”;
notSure = true;
不能直接使用
notSure.toFixed(); Error: Object is of type 'unknown'
必须使用类型检查
if (typeof notSure === “number”) {
console.log(notSure.toFixed(2)); OK
}
if (typeof notSure === “string”) {
console.log(notSure.toUpperCase()); OK
}
类型断言
const value: unknown = “hello”;
const str: string = value as string;
使用类型守卫函数
function isString(value: unknown): value is string {
return typeof value === “string”;
}
if (isString(notSure)) {
console.log(notSure.length); OK,TypeScript 知道是 string
}
```
==== 3.2.3 never 永不类型 ====
never 表示永远不会发生的值,用于:
- 抛出异常的函数
- 无限循环的函数
- exhaustive type checking
```typescript
抛出错误的函数返回 never
function throwError(message: string): never {
throw new Error(message);
}
无限循环
function infiniteLoop(): never {
while (true) {
console.log(“Looping…”);
}
}
exhaustive checking
function assertNever(x: never): never {
throw new Error(“Unexpected object: ” + x);
}
type Shape =
| { kind: “circle”; radius: number }
| { kind: “square”; side: number }
| { kind: “triangle”; base: number; height: number };
function getArea(shape: Shape): number {
switch (shape.kind) {
case “circle”:
return Math.PI * shape.radius 2;
case “square”:
return shape.side 2;
case “triangle”:
return (shape.base * shape.height) / 2;
default:
return assertNever(shape); 如果 Shape 新增类型,这里会报错
}
}
```
==== 3.2.4 void 空类型 ====
void 表示没有返回值,通常用于函数。
```typescript
无返回值的函数
function logMessage(message: string): void {
console.log(message);
}
function processData(data: unknown): void {
处理数据,不返回结果
saveToDatabase(data);
}
void 类型的变量只能赋值 undefined 或 null
let unusable: void = undefined;
unusable = null; 在 strictNullChecks 下可能报错
实际上 void 类型的变量很少使用
```
==== 3.2.5 null 和 undefined ====
```typescript
undefined
let u: undefined = undefined;
null
let n: null = null;
strictNullChecks 开启时的区别
let str: string = “hello”;
str = null; Error
str = undefined; Error
let nullableStr: string | null = null; OK
nullableStr = “hello”; OK
let optionalStr: string | undefined = undefined; OK
optionalStr = “hello”; OK
非空断言(谨慎使用)
function getLength(str: string | null): number {
return str!.length; ! 告诉 TypeScript str 不为 null
}
更安全的做法
function getLengthSafe(str: string | null): number {
return str ? str.length : 0;
}
```
===== 3.3 数组类型(Array Types) =====
==== 3.3.1 数组类型注解 ====
```typescript
类型[] 语法
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: string[] = [“a”, “b”, “c”];
let booleans: boolean[] = [true, false, true];
Array<类型> 语法(泛型)
let numbers2: Array<number> = [1, 2, 3];
let strings2: Array<string> = [“a”, “b”, “c”];
混合类型数组(不推荐)
let mixed: (string | number)[] = [“a”, 1, “b”, 2];
对象数组
interface User {
id: number;
name: string;
}
let users: User[] = [
{ id: 1, name: “Alice” },
{ id: 2, name: “Bob” }
];
多维数组
let matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
let threeDArray: number[][][] = [1, 2, 3, 4];
```
==== 3.3.2 数组方法类型 ====
```typescript
const numbers: number[] = [1, 2, 3, 4, 5];
不改变原数组的方法
const doubled: number[] = numbers.map(n ⇒ n * 2);
const evens: number[] = numbers.filter(n ⇒ n % 2 === 0);
const sum: number = numbers.reduce1); 42
console.log(parseValue(true)); true
console.log(parseValue(null)); null
console.log(parseValue(undefined)); null
console.log(parseValue({})); null
```
</details>
==== 练习 4:元组与对象转换 ====
实现以下类型转换函数:
```typescript
interface Point {
x: number;
y: number;
}
1. 将 Point 对象转换为元组 [x, y]
function pointToTuple(point: Point): [number, number] {
实现
}
2. 将元组 [x, y] 转换为 Point 对象
function tupleToPoint(tuple: [number, number]): Point {
实现
}
3. 交换元组中的两个元素
function swap<T, U>(tuple: [T, U]): [U, T] {
实现
}
```
<details>
<summary>参考答案</summary>
```typescript
interface Point {
x: number;
y: number;
}
1. 对象转元组
function pointToTuple(point: Point): [number, number] {
return [point.x, point.y];
}
2. 元组转对象
function tupleToPoint(tuple: [number, number]): Point {
const [x, y] = tuple;
return { x, y };
}
3. 交换元组元素
function swap<T, U>(tuple: [T, U]): [U, T] {
const [first, second] = tuple;
return [second, first];
}
测试
const point: Point = { x: 10, y: 20 };
const tuple = pointToTuple(point); [10, 20]
const backToPoint = tupleToPoint(tuple); { x: 10, y: 20 }
const swapped = swap([“hello”, 42]); [42, “hello”]
```
</details>
===== 扩展阅读 =====
- 下一章:枚举与字面量类型
- TypeScript 官方文档 - 基础类型
- TypeScript 官方文档 - 日常类型