跳到主要内容

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),nullundefined 只能赋值给它们自己和 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 的基础类型:

  1. 基本类型:stringnumberbooleanvoidnullundefined
  2. 数组和元组
  3. 枚举类型
  4. anyunknownnever 类型
  5. object 类型
  6. 类型断言
  7. 字面量类型
  8. 类型别名

练习

  1. 定义一个包含用户信息的元组(姓名、年龄、邮箱)
  2. 创建一个表示星期的枚举
  3. 使用字面量类型定义一个表示状态的类型
  4. 编写一个函数,参数可能是字符串或数字,返回对应的长度