TypeScript 5.x 进阶用法:装饰器、条件类型与性能优化实战

By | 2026年7月14日

引言

TypeScript 5.x 带来了许多激动人心的新特性,尤其是装饰器的标准化、条件类型的增强以及类型系统性能的显著提升。然而,许多开发者仍停留在基础用法上,未能充分利用这些特性来提升代码质量。本文将带你深入实践,掌握 TypeScript 5.x 的进阶用法,包括装饰器、条件类型以及性能优化技巧。

一、装饰器:从实验到标准

TypeScript 5.x 正式实现了 Stage 3 装饰器提案,与之前的实验性装饰器有显著差异。新装饰器更简洁、类型安全,并且与 JavaScript 标准对齐。

1.1 启用新装饰器

tsconfig.json 中设置:


{
    "compilerOptions": {
        "target": "ES2022",
        "experimentalDecorators": false // 关闭旧装饰器
    }
}

1.2 基本用法

新装饰器函数接收两个参数:target(被装饰的元素)和 context(包含元数据的对象)。


function logged<T extends (...args: any[]) => any>(
    target: T,
    context: ClassMethodDecoratorContext
) {
    return function (this: any, ...args: Parameters<T>) {
        console.log(`Calling ${String(context.name)} with`, args);
        return target.call(this, ...args);
    };
}

class Calculator {
    @logged
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(2, 3); // 输出日志

💡 注意:新装饰器不能用于参数装饰器;如果需要参数装饰器,仍需使用旧装饰器(experimentalDecorators: true),但两者不可混用。

1.3 自定义装饰器工厂

装饰器工厂返回一个装饰器函数,可以接受参数:


function validate(min: number, max: number) {
    return function (
        target: any,
        context: ClassAccessorDecoratorContext
    ) {
        return {
            get(this: any) {
                return target.get.call(this);
            },
            set(this: any, value: number) {
                if (value < min || value > max) {
                    throw new Error(`Value must be between ${min} and ${max}`);
                }
                target.set.call(this, value);
            }
        };
    };
}

class Temperature {
    @validate(0, 100)
    accessor celsius: number = 0;
}

const temp = new Temperature();
temp.celsius = 50; // 正常
temp.celsius = 150; // 抛出错误

二、条件类型:从基础到高级模式

条件类型让类型计算变得灵活,TypeScript 5.x 进一步增强了其能力。

2.1 分布式条件类型

当条件类型用于泛型且泛型为联合类型时,会自动分布式求值:


type ToArray<T> = T extends unknown ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]

2.2 模板字面量类型与条件类型结合


type EventName<T extends string> = `${T}Changed`;
type Handler<T extends string> = (event: EventName<T>) => void;

function createListener<T extends string>(event: T, handler: Handler<T>) {}

createListener('name', (event) => {
    // event 类型为 "nameChanged"
});

2.3 infer 关键字的高级用法

infer 用于在条件类型中推断类型变量:


type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;

function greet() { return 'hello'; }
type GreetReturn = ReturnTypeOf<typeof greet>; // string

更复杂的例子:提取 Promise 的返回值类型:


type Unwrap<T> = T extends Promise<infer U> ? Unwrap<U> : T;
type Result = Unwrap<Promise<Promise<string>>>; // string

💡 注意infer 只能在条件类型的 extends 子句中使用。

三、性能优化:让类型检查飞起来

TypeScript 5.x 通过多种方式提升了类型检查性能。

3.1 使用 --isolatedModules--verbatimModuleSyntax

这两个选项可以显著减少编译时的类型检查工作:


{
    "compilerOptions": {
        "isolatedModules": true,
        "verbatimModuleSyntax": true
    }
}
  • isolatedModules:确保每个文件可以独立编译,避免跨文件类型推断。
  • verbatimModuleSyntax:保留模块语法,避免不必要的类型擦除。

3.2 避免大型联合类型

大型联合类型(超过 50 个成员)会严重影响性能。使用接口或类型映射替代:


// 不推荐
type Status = 'a' | 'b' | ... | 'z'; // 26个

// 推荐
interface StatusMap {
    a: any;
    b: any;
    // ...
}
type Status = keyof StatusMap;

3.3 使用 @ts-expect-error 替代 @ts-ignore

@ts-ignore 会跳过类型检查,但可能隐藏错误。@ts-expect-error 更安全:


// @ts-expect-error - 下一行预期有错误
const x: number = 'string'; // 错误被预期,不会报错

3.4 利用 satisfies 操作符

satisfies 在 4.9 引入,5.x 增强,用于验证类型但不改变推断结果:


const palette = {
    red: [255, 0, 0],
    green: '#00ff00',
} satisfies Record<string, string | number[]>;

// palette.red 推断为 number[],而非 string | number[]
palette.red.map(x => x); // 正确

四、实战:构建类型安全的 API 客户端

结合上述特性,我们构建一个类型安全的 HTTP 客户端。


// 定义 API 端点类型
type Endpoint = {
    '/users': { method: 'GET'; response: User[] };
    '/users/:id': { method: 'GET'; response: User };
    '/users': { method: 'POST'; body: Omit<User, 'id'>; response: User };
};

// 条件类型提取响应类型
type ResponseOf<T extends keyof Endpoint> = Endpoint[T] extends { response: infer R } ? R : never;

// 请求函数
async function request<T extends keyof Endpoint>(
    url: T,
    options?: { method?: Endpoint[T]['method']; body?: any }
): Promise<ResponseOf<T>> {
    const response = await fetch(url, options);
    return response.json();
}

// 使用
const users = await request('/users'); // 类型为 User[]
const user = await request('/users/:id', { method: 'GET' }); // 类型为 User

五、总结

TypeScript 5.x 的装饰器、条件类型和性能优化为开发者提供了更强大的工具。通过本文的实践,你应该能够:

  • 使用新装饰器编写元编程代码
  • 利用条件类型进行复杂的类型计算
  • 优化项目配置以提升类型检查速度

下一步,可以探索 TypeScript 5.x 的模块解析策略(moduleResolution: 'bundler')以及迭代器辅助方法(Iterator 类型)等特性。

延伸阅读