mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1138 字
3 分钟
TypeScript 进阶指南

TypeScript 进阶指南#

TypeScript已经成为现代JavaScript开发的重要工具,它通过静态类型检查帮助我们在开发过程中发现错误,提高代码质量和可维护性。本文将探讨TypeScript的高级特性和最佳实践,帮助你更深入地理解和使用TypeScript。

1. 高级类型系统#

1.1 泛型#

泛型是TypeScript中最强大的特性之一,它允许我们编写可重用的组件,这些组件可以与多种类型一起工作,而不是单一类型。

// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
// 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}

1.2 条件类型#

条件类型允许我们根据类型之间的关系选择类型。

// 条件类型
type IsString<T> = T extends string ? true : false;
// 测试
type A = IsString<string>; // true
type B = IsString<number>; // false

1.3 映射类型#

映射类型允许我们基于旧类型创建新类型。

// 映射类型
interface Person {
name: string;
age: number;
}
// 使所有属性变为可选
type Partial<T> = {
[P in keyof T]?: T[P];
};
// 使所有属性变为只读
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// 测试
const person: Partial<Person> = { name: "John" };
const readonlyPerson: Readonly<Person> = { name: "John", age: 30 };
// readonlyPerson.age = 31; // 错误:无法修改只读属性

1.4 模板字面量类型#

模板字面量类型允许我们使用模板字符串语法创建新的字符串类型。

// 模板字面量类型
type EventName<T extends string> = `${T}Event`;
// 测试
type ClickEvent = EventName<"click">; // "clickEvent"
type MouseEvent = EventName<"mouse">; // "mouseEvent"
// 联合类型
type Direction = "up" | "down" | "left" | "right";
type DirectionEvent = `${Direction}Event`; // "upEvent" | "downEvent" | "leftEvent" | "rightEvent"

2. 类型推断和类型守卫#

2.1 类型断言#

类型断言允许我们告诉TypeScript编译器某个值的类型,即使编译器无法推断出该类型。

// 类型断言
const someValue: unknown = "this is a string";
const strLength: number = (someValue as string).length;
// 或使用尖括号语法
const strLength2: number = (<string>someValue).length;

2.2 类型守卫#

类型守卫允许我们在运行时检查值的类型,从而在类型系统中缩小类型范围。

// 类型守卫函数
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function isArray(value: unknown): value is unknown[] {
return Array.isArray(value);
}
// 使用类型守卫
function processValue(value: unknown) {
if (isString(value)) {
// 这里value被推断为string类型
console.log(value.toUpperCase());
} else if (isNumber(value)) {
// 这里value被推断为number类型
console.log(value.toFixed(2));
} else if (isArray(value)) {
// 这里value被推断为unknown[]类型
console.log(value.length);
} else {
console.log("Unknown type");
}
}

2.3 类型谓词#

类型谓词是类型守卫函数的返回类型,它告诉TypeScript编译器如何缩小类型范围。

// 类型谓词
interface Cat {
meow: () => void;
}
interface Dog {
bark: () => void;
}
function isCat(animal: Cat | Dog): animal is Cat {
return "meow" in animal;
}
function makeSound(animal: Cat | Dog) {
if (isCat(animal)) {
// 这里animal被推断为Cat类型
animal.meow();
} else {
// 这里animal被推断为Dog类型
animal.bark();
}
}

3. 模块和命名空间#

3.1 ES模块#

TypeScript支持ES模块系统,这是现代JavaScript中推荐的模块系统。

math.ts
// 导出
export function add(a: number, b: number): number {
return a + b;
}
export const PI = 3.14;
// 导入
// app.ts
import { add, PI } from "./math";
console.log(add(1, 2)); // 3
console.log(PI); // 3.14
// 命名导入
import * as MathUtils from "./math";
console.log(MathUtils.add(1, 2)); // 3

3.2 命名空间#

命名空间是TypeScript中组织代码的另一种方式,它允许我们将相关的代码分组到一个命名空间中。

// 命名空间
namespace Geometry {
export interface Point {
x: number;
y: number;
}
export function distance(p1: Point, p2: Point): number {
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
}
}
// 使用命名空间
const p1: Geometry.Point = { x: 0, y: 0 };
const p2: Geometry.Point = { x: 3, y: 4 };
console.log(Geometry.distance(p1, p2)); // 5

4. 高级接口和类型#

4.1 接口继承#

接口可以继承其他接口,从而复用和扩展类型定义。

// 接口继承
interface Shape {
area(): number;
}
interface Circle extends Shape {
radius: number;
}
interface Rectangle extends Shape {
width: number;
height: number;
}
// 实现接口
class CircleImpl implements Circle {
constructor(public radius: number) {}
area(): number {
return Math.PI * this.radius ** 2;
}
}
class RectangleImpl implements Rectangle {
constructor(public width: number, public height: number) {}
area(): number {
return this.width * this.height;
}
}

4.2 交叉类型#

交叉类型允许我们将多个类型合并为一个类型。

// 交叉类型
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
// 交叉类型
type EmployeePerson = Person & Employee;
// 测试
const employee: EmployeePerson = {
name: "John",
employeeId: 123
};

4.3 联合类型#

联合类型允许我们表示一个值可以是多种类型中的一种。

// 联合类型
type StringOrNumber = string | number;
function processValue(value: StringOrNumber) {
if (typeof value === "string") {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
// 测试
processValue("hello"); // HELLO
processValue(123); // 123.00

5. 装饰器#

装饰器是一种特殊类型的声明,它可以附加到类声明、方法、访问器、属性或参数上。装饰器使用@expression语法,其中expression必须求值为一个函数,该函数会在运行时被调用,传入装饰的声明信息。

5.1 类装饰器#

// 类装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}

5.2 方法装饰器#

// 方法装饰器
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}

5.3 属性装饰器#

// 属性装饰器
function format(target: any, propertyKey: string) {
let value = target[propertyKey];
// 替换getter
const getter = function () {
return "[Formatted] " + value;
};
// 替换setter
const setter = function (newVal: string) {
value = newVal;
};
// 重新定义属性
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Greeter {
@format
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
const greeter = new Greeter("world");
console.log(greeter.greet()); // Hello, [Formatted] world

6. 高级配置#

6.1 tsconfig.json 配置#

tsconfig.json文件用于配置TypeScript编译器的行为。

{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}

6.2 类型声明文件#

类型声明文件(.d.ts)用于为JavaScript库提供类型信息。

my-lib.d.ts
// 类型声明文件示例
declare module "my-lib" {
export function greet(name: string): string;
export const version: string;
}
// 使用
import { greet, version } from "my-lib";
console.log(greet("John"));
console.log(version);

7. 最佳实践#

7.1 使用严格模式#

启用严格模式可以帮助我们发现更多的类型错误,提高代码质量。

{
"compilerOptions": {
"strict": true
}
}

7.2 使用类型别名#

对于复杂的类型,使用类型别名可以提高代码的可读性。

// 类型别名
type UserId = string | number;
type User = {
id: UserId;
name: string;
email: string;
};

7.3 避免使用any类型#

any类型会关闭TypeScript的类型检查,应该尽量避免使用。

错误示例:

function processValue(value: any) {
// 没有类型检查
return value.doSomething();
}

正确示例:

interface Processable {
doSomething(): void;
}
function processValue(value: Processable) {
// 有类型检查
return value.doSomething();
}

7.4 使用unknown类型#

对于未知类型的值,使用unknown类型而不是any类型,因为unknown类型更加安全。

function processValue(value: unknown) {
if (typeof value === "string") {
return value.toUpperCase();
} else if (typeof value === "number") {
return value.toFixed(2);
}
return "Unknown type";
}

7.5 使用类型守卫#

使用类型守卫可以帮助TypeScript编译器更好地推断类型。

function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === "string");
}
function processValue(value: unknown) {
if (isStringArray(value)) {
// 这里value被推断为string[]类型
return value.map(item => item.toUpperCase());
}
return [];
}

8. 常见错误和解决方案#

8.1 类型不匹配#

问题: 类型不匹配导致编译错误。

解决方案: 确保类型一致,或使用类型断言。

// 类型不匹配
const value: number = "123"; // 错误:类型"string"不能赋值给类型"number"
// 解决方案1:确保类型一致
const value: number = 123;
// 解决方案2:使用类型断言
const value: number = parseInt("123");

8.2 可选属性访问#

问题: 访问可能不存在的属性导致编译错误。

解决方案: 使用可选链操作符。

interface Person {
name: string;
address?: {
street?: string;
};
}
const person: Person = { name: "John" };
// 错误:无法访问可能不存在的属性
console.log(person.address.street);
// 正确:使用可选链操作符
console.log(person.address?.street); // undefined

8.3 空值检查#

问题: 访问可能为null或undefined的值导致编译错误。

解决方案: 使用空值合并操作符或条件检查。

const value: string | null = null;
// 错误:无法访问可能为null的值
console.log(value.length);
// 解决方案1:使用条件检查
if (value !== null) {
console.log(value.length);
}
// 解决方案2:使用空值合并操作符
console.log(value?.length ?? 0); // 0

9. 总结#

TypeScript是一种强大的静态类型语言,它通过类型系统帮助我们编写更安全、更可维护的代码。通过掌握本文介绍的高级特性和最佳实践,你可以:

  • 编写更具可重用性的代码
  • 提高代码的类型安全性
  • 减少运行时错误
  • 提高代码的可维护性

希望本文对你有所帮助,祝你编码愉快!

10. 参考资料#

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

TypeScript 进阶指南
https://sakumonet.top/posts/typescript-advanced-guide/
作者
SakuMonet
发布于
2026-02-26
许可协议
Unlicensed

部分信息可能已经过时