typescript中的难点总结
TypeScript 虽然在 JavaScript 基础上增加了类型系统,但在实际使用中仍有一些复杂和容易混淆的概念。以下是 TypeScript 中的主要难点总结:
1. 复杂类型系统
泛型约束与条件类型
// 泛型约束
interface Lengthwise {length: number;
}function logLength<T extends Lengthwise>(arg: T): T {console.log(arg.length);return arg;
}// 条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; // true
type B = IsString<123>; // false// 映射类型中的条件判断
type ExtractPropertyNames<T, U> = {[K in keyof T]: T[K] extends U ? K : never;
}[keyof T];
类型推断与类型收窄
// 类型保护
function isString(value: unknown): value is string {return typeof value === 'string';
}function processValue(value: string | number) {if (isString(value)) {// 这里 value 被收窄为 stringconsole.log(value.toUpperCase());} else {// 这里 value 被收窄为 numberconsole.log(value.toFixed(2));}
}
2. 高级类型技巧
模板字面量类型
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiEndpoint = `/${string}`;
type FullEndpoint = `${HttpMethod} ${ApiEndpoint}`;type UserAction = 'create' | 'update' | 'delete';
type EventName = `${UserAction}_user`;// 字符串操作类型
type Getter<T extends string> = `get${Capitalize<T>}`;
type NameGetters = Getter<'name' | 'age'>; // "getName" | "getAge"
递归类型
// 递归类型定义
type Json = | string| number| boolean| null| { [key: string]: Json }| Json[];// 递归工具类型
type DeepReadonly<T> = {readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]>: T[P];
}type DeepPartial<T> = {[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]>: T[P];
}
3. 声明合并
// 接口合并
interface User {name: string;
}interface User {age: number;
}// 最终 User 接口为:
// interface User {
// name: string;
// age: number;
// }// 命名空间合并
namespace Validation {export interface StringValidator {isAcceptable(s: string): boolean;}
}namespace Validation {export class LettersOnlyValidator implements StringValidator {isAcceptable(s: string) {return /^[A-Za-z]+$/.test(s);}}
}
4. 装饰器元编程
// 类装饰器
function Logger<T extends { new (...args: any[]): {} }>(constructor: T) {return class extends constructor {constructor(...args: any[]) {super(...args);console.log(`Created instance of ${constructor.name}`);}};
}// 方法装饰器
function LogMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Calling ${propertyName} with args:`, args);return originalMethod.apply(this, args);};return descriptor;
}@Logger
class Calculator {@LogMethodadd(a: number, b: number): number {return a + b;}
}
5. 模块和类型解析
类型引用和路径映射
// tsconfig.json 中的路径映射
{"compilerOptions": {"baseUrl": ".","paths": {"@/*": ["src/*"],"@/components/*": ["src/components/*"]}}
}// 三斜线指令
/// <reference types="node" />
/// <reference path="./types.d.ts" />
6. 泛型进阶用法
泛型约束与默认值
// 复杂的泛型约束
interface Entity {id: number;
}interface User extends Entity {name: string;
}interface Product extends Entity {title: string;price: number;
}// 泛型工厂函数
function createRepository<T extends Entity, K extends keyof T>() {return class Repository {private items: T[] = [];findById(id: number): T | undefined {return this.items.find(item => item.id === id);}findByField(field: K, value: T[K]): T | undefined {return this.items.find(item => item[field] === value);}};
}const UserRepository = createRepository<User, keyof User>();
逆变、协变和双向协变
// 协变示例
interface Animal {name: string;
}interface Dog extends Animal {breed: string;
}let animals: Animal[] = [];
let dogs: Dog[] = [];animals = dogs; // 协变 - 允许
// dogs = animals; // 错误 - 不允许// 逆变示例(函数参数)
type AnimalHandler = (animal: Animal) => void;
type DogHandler = (dog: Dog) => void;let animalHandler: AnimalHandler = (animal: Animal) => { };
let dogHandler: DogHandler = (dog: Dog) => { };// dogHandler = animalHandler; // 协变 - 允许(strictFunctionTypes 下不允许)
// animalHandler = dogHandler; // 逆变 - 允许
7. 工具类型深度使用
// 内置工具类型进阶用法
type RequiredByKeys<T, K extends keyof T = keyof T> = Omit<T, K> & Required<Pick<T, K>>;type PartialByKeys<T, K extends keyof T = keyof T> = Omit<T, K> & Partial<Pick<T, K>>;// 条件类型与 infer 关键字
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type MyParameters<T> = T extends (...args: infer P) => any ? P : never;// 递归工具类型
type Nullable<T> = {[P in keyof T]: T[P] | null;
};type DeepNullable<T> = {[P in keyof T]: T[P] extends object ? DeepNullable<T[P]> | null: T[P] | null;
};
8. 命名空间和模块的混合使用
// 命名空间中的模块导出
namespace Shapes {export interface Point {x: number;y: number;}export class Rectangle {constructor(public width: number, public height: number) {}}
}// 模块中的命名空间导出
export module Geometry {export interface Vector {x: number;y: number;z: number;}export class Matrix {// 矩阵实现}
}
9. 配置复杂性
tsconfig.json 复杂配置
{"compilerOptions": {"strict": true,"noImplicitAny": true,"strictNullChecks": true,"strictFunctionTypes": true,"strictBindCallApply": true,"strictPropertyInitialization": true,"noImplicitThis": true,"noImplicitReturns": true,"exactOptionalPropertyTypes": true,"noUncheckedIndexedAccess": true,"noImplicitOverride": true}
}
10. 第三方库类型定义
声明文件编写
// 为第三方库编写类型声明
declare module 'my-untyped-library' {interface LibraryOptions {timeout?: number;retries?: number;}export function initialize(options: LibraryOptions): void;export function doSomething(input: string): Promise<string>;
}// 全局类型扩展
declare global {interface Window {myCustomProperty: string;}namespace NodeJS {interface ProcessEnv {NODE_ENV: 'development' | 'production' | 'test';API_URL: string;}}
}
这些难点需要在实际开发中不断实践和总结,才能更好地掌握 TypeScript 的强大功能。