初级 TypeScript 开发者常见错误:进阶篇

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

初级 TypeScript 开发者常见错误:进阶篇



TypeScript 是一个强大的工具,有助于编写更安全、更可预测的代码。然而,从 JavaScript 迁移到 TypeScript,尤其是在进阶层面,常常伴随着特定的错误。即使是熟悉类型化基础的开发者,在处理泛型、条件类型和重载时也会犯典型错误。本文将剖析进阶新手最常犯的 4 个错误,并展示如何修正它们。



1. 泛型使用不当:丢失类型信息



最常见的错误之一是泛型声明过于宽泛或过于狭窄。开发者经常在泛型函数内部指定 any 类型,完全抵消了 TypeScript 的优势。



问题

// 不好:函数返回 any,丢失类型化function getProperty(obj: any, key: string): any {    return obj[key];}

const user = { name: 'Alice', age: 30 };const value = getProperty(user, 'name'); // value: any


解决方案

// 好:使用泛型保留类型function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {    return obj[key];}

const user = { name: 'Alice', age: 30 };const value = getProperty(user, 'name'); // value: string


重要提示:始终对泛型使用 extends 约束。这不仅保留类型,还能在 IDE 中提供自动补全功能。



2. 滥用 any 类型而非 unknown



许多初级开发者在无法立即确定类型时,到处使用 any。这完全破坏了 TypeScript 的优势。正确的方法是使用 unknown,然后收窄类型。



问题

// 不好:any 允许任何操作function parseData(data: any): void {    console.log(data.toUpperCase()); // 如果 data 是数字,运行时出错    data.someMethod(); // 没有任何检查}


解决方案

// 好:unknown 要求进行类型检查function parseData(data: unknown): void {    if (typeof data === 'string') {        console.log(data.toUpperCase()); // 安全    } else if (Array.isArray(data)) {        console.log(data.length);    } else {        console.log('未知数据类型');    }}


仅在极端情况下使用 any(例如从 JS 迁移或处理动态 API)。其他所有情况都应使用 unknown 配合类型守卫。



3. 函数重载错误



TypeScript 中的函数重载是一个强大但棘手的机制。典型错误:签名顺序错误或实现与声明的重载不匹配。



问题

// 不好:签名相互矛盾function process(value: string): string;function process(value: number): number;function process(value: string | number): string | number {    // 实现未涵盖所有情况    return value.toString(); // 返回 string,但为 number 类型承诺返回 number}


解决方案

// 好:清晰的逻辑分离function process(value: string): string;function process(value: number): number;function process(value: string | number): string | number {    if (typeof value === 'string') {        return value.toUpperCase(); // 返回 string    } else {        return value * 2; // 返回 number    }}

const result1 = process('hello'); // stringconst result2 = process(10); // number


建议:始终检查函数实现是否覆盖了签名中声明的所有变体。使用 typeof 或自定义类型守卫。



4. 忽略严格模式编译

博客

书籍推荐