TypeScript 基础类型
TypeScript 支持与 JavaScript 相同的数据类型,并添加了额外的类型如枚举。
基本类型
字符串 (string)
let name: string = "张三";
let greeting: string = `你好,${name}`;
// 模板字符串
let message: string = `
多行字符串
第二行
`;
解释:string 类型表示文本数据,可以使用单引号、双引号或模板字符串。
数字 (number)
let decimal: number = 6;
let hex: number = 0xf00d; // 十六进制
let binary: number = 0b1010; // 二进制
let octal: number = 0o744; // 八进制
let float: number = 3.14;
解释:TypeScript 中的所有数字都是浮点数,number 类型涵盖整数和浮点数。
布尔值 (boolean)
let isDone: boolean = false;
let hasPermission: boolean = true;
// 布尔表达式
let isActive: boolean = 10 > 5; // true
空值 (void, null, undefined)
// void - 表示没有任何类型
function log(message: string): void {
console.log(message);
}
// null 和 undefined
let u: undefined = undefined;
let n: null = null;
// 默认情况下 null 和 undefined 是所有类型的子类型
let num: number = null; // 严格模式下会报错
let str: string = undefined; // 严格模式下会报错
解释:在严格模式下(strictNullChecks: true),null 和 undefined 只能赋值给它们自己和 void 类型。
数组
基本数组
// 方式一:元素类型后面接 []
let numbers: number[] = [1, 2, 3, 4, 5];
let names: string[] = ["张三", "李四", "王五"];
// 方式二:使用数组泛型
let list: Array<number> = [1, 2, 3];
let items: Array<string> = ["a", "b", "c"];
// 只读数组
let readonlyArray: ReadonlyArray<number> = [1, 2, 3];
// readonlyArray[0] = 4; // 错误
// readonlyArray.push(4); // 错误
解释:数组类型确保数组中所有元素都是相同类型。ReadonlyArray 创建不可变数组。
多维数组
let matrix: number[][] = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
元组 (Tuple)
元组允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
// 定义元组
let person: [string, number] = ["张三", 25];
// 访问元素
console.log(person[0]); // "张三"
console.log(person[1]); // 25
// 正确的类型操作
person[0] = "李四"; // OK
person[1] = 30; // OK
// 错误的类型
// person[0] = 123; // 错误:不能将 number 赋给 string
// 越界元素会被标记为联合类型
person.push(true); // 严格模式下会报错
解释:元组适合表示固定长度和类型的数组,如坐标点 [x, y] 或键值对 [key, value]。
只读元组
let point: readonly [number, number] = [10, 20];
// point[0] = 5; // 错误
// point.push(30); // 错误
枚举 (enum)
枚举用于定义一组命名的常量。
数字枚举
enum Direction {
Up = 1,
Down,
Left,
Right
}
let dir: Direction = Direction.Up; // 1
let dirName: string = Direction[2]; // "Down"
// 默认从 0 开始
enum Color {
Red, // 0
Green, // 1
Blue // 2
}
let color: Color = Color.Red; // 0
解释:数字枚举的值会自动递增。可以手动指定起始值。
字符串枚举
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
let dir: Direction = Direction.Up; // "UP"
混合枚举
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES"
}
常量枚举
const enum Direction {
Up,
Down,
Left,
Right
}
let dir = Direction.Up; // 编译后:let dir = 0
解释:常量枚举在编译时会被内联,不会生成额外的代码,适合性能敏感场景。
any 类型
any 类型可以表示任意类型,相当于关闭类型检查。
let anything: any = 4;
anything = "hello"; // OK
anything = true; // OK
anything = [1, 2, 3]; // OK
// any 类型的变量可以调用任意方法
anything.toFixed(); // OK(运行时可能出错)
anything.whatever(); // OK(运行时可能出错)
// 任何类型的值都可以赋给 any
let a: any = 123;
let b: number = a; // OK
解释:any 类型应该尽量避免使用,它会失去 TypeScript 的类型检查优势。只在迁移旧代码或不确定类型时使用。
unknown 类型
unknown 是类型安全的 any,使用前必须进行类型检查。
let value: unknown;
value = 123; // OK
value = "hello"; // OK
value = true; // OK
// 不能直接使用
// value.toFixed(); // 错误
// 必须先进行类型检查
if (typeof value === "number") {
console.log(value.toFixed(2)); // OK
}
// 使用类型断言
(value as string).toUpperCase();
// 类型守卫
function isString(val: unknown): val is string {
return typeof val === "string";
}
if (isString(value)) {
console.log(value.toUpperCase()); // OK
}
解释:推荐使用 unknown 替代 any,它强制在使用前进行类型检查,更安全。
never 类型
never 类型表示永远不会发生的类型。
// 永远不会有返回值的函数
function error(message: string): never {
throw new Error(message);
}
// 无限循环
function infiniteLoop(): never {
while (true) {}
}
// 类型守卫中的 never
function checkType(value: string | number): string {
if (typeof value === "string") {
return "string";
} else if (typeof value === "number") {
return "number";
}
// 这里必须是 never,因为所有情况都已处理
const _exhaustiveCheck: never = value;
return _exhaustiveCheck;
}
解释:never 常用于表示不可能到达的代码路径,或确保 switch 语句覆盖所有情况。
object 类型
object 类型表示非原始类型。
let obj: object = {
name: "张三",
age: 25
};
// 原始类型不能赋给 object
// obj = 123; // 错误
// obj = "hello"; // 错误
// obj = true; // 错误
// 但可以赋值对象、数组、函数等
obj = [1, 2, 3];
obj = function() {};
obj = new Date();
类型断言
类型断言告诉编译器"相信我,我知道我在做什么"。
两种语法
let someValue: any = "Hello World";
// 方式一:尖括号语法
let strLength1: number = (<string>someValue).length;
// 方式二:as 语法(推荐)
let strLength2: number = (someValue as string).length;
解释:在 JSX 中只能使用 as 语法,所以推荐统一使用 as 语法。
常见用法
// DOM 元素断言
const input = document.getElementById("input") as HTMLInputElement;
input.value = "hello";
// 联合类型断言
function getLength(value: string | number): number {
if ((value as string).length) {
return (value as string).length;
}
return value.toString().length;
}
// 非空断言
let element: HTMLElement | null = document.getElementById("app");
element!.innerHTML = "Hello"; // 断言 element 不为 null
字面量类型
字面量类型指定具体的值。
// 字符串字面量
let direction: "up" | "down" | "left" | "right";
direction = "up"; // OK
// direction = "up-left"; // 错误
// 数字字面量
let dice: 1 | 2 | 3 | 4 | 5 | 6;
dice = 3; // OK
// dice = 7; // 错误
// 布尔字面量
let success: true = true;
// success = false; // 错误
// 实际应用
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function request(method: HttpMethod, url: string) {
// ...
}
request("GET", "/api/users"); // OK
// request("PATCH", "/api/users"); // 错误
解释:字面量类型结合联合类型可以定义精确的值范围,非常实用。
类型别名
使用 type 关键字创建类型别名。
// 基本类型别名
type Name = string;
type Age = number;
// 联合类型别名
type ID = string | number;
// 对象类型别名
type User = {
name: string;
age: number;
email?: string;
};
// 函数类型别名
type Callback = (data: string) => void;
// 使用类型别名
let userName: Name = "张三";
let userId: ID = 123;
let user: User = {
name: "张三",
age: 25
};
小结
本章我们学习了 TypeScript 的基础类型:
- 基本类型:
string、number、boolean、void、null、undefined - 数组和元组
- 枚举类型
any、unknown、never类型object类型- 类型断言
- 字面量类型
- 类型别名
练习
- 定义一个包含用户信息的元组(姓名、年龄、邮箱)
- 创建一个表示星期的枚举
- 使用字面量类型定义一个表示状态的类型
- 编写一个函数,参数可能是字符串或数字,返回对应的长度