TypeScript 高级特性详解

TypeScript 高级特性详解

引言

TypeScript 是 JavaScript 的超集,为 JavaScript 添加了静态类型检查和面向对象编程的能力。随着前端应用日益复杂,TypeScript 的高级特性变得越来越重要。本文将深入探讨 TypeScript 的几个核心高级特性,帮助开发者更好地理解和运用这些强大功能。

一、泛型编程(Generic Programming)

1.1 泛型基础概念

泛型(Generic)是 TypeScript 中最强大的特性之一,它允许我们创建可重用的组件,这些组件可以处理不同类型的数据而不丢失类型安全性。

typescript 复制代码
// 基础泛型函数
function identity<T>(arg: T): T {
    return arg;
}

// 使用泛型函数
let output1 = identity<string>("myString");
let output2 = identity<number>(42);
let output3 = identity("myString"); // 类型推断

1.2 泛型约束

有时候我们需要对泛型参数施加一定的约束,确保传入的类型具有某些特定的属性或方法。

typescript 复制代码
// 定义约束接口
interface Lengthwise {
    length: number;
}

// 使用 extends 关键字添加约束
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // 现在我们知道它有 .length 属性
    return arg;
}

loggingIdentity("hello"); // 正确,字符串有 length 属性
loggingIdentity([1, 2, 3]); // 正确,数组有 length 属性
// loggingIdentity(3); // 错误,数字没有 length 属性

1.3 泛型类

泛型也可以应用于类,使类能够处理多种类型的值。

typescript 复制代码
class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
    
    constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
        this.zeroValue = zeroValue;
        this.add = addFn;
    }
}

let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
console.log(myGenericNumber.add(5, 10)); // 15

let stringNumeric = new GenericNumber<string>("", (x, y) => x + y);
console.log(stringNumeric.add("hello", "world")); // "helloworld"

1.4 泛型接口

泛型接口可以描述那些跨越多种类型的通用调用签名。

typescript 复制代码
interface GenericIdentityFn<T> {
    (arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

1.5 多个泛型参数

函数和类可以接受多个泛型参数,提供更多灵活性。

typescript 复制代码
function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

console.log(swap(["hello", 123])); // [123, "hello"]

class KeyValuePair<TKey, TValue> {
    private key: TKey;
    private value: TValue;
    
    constructor(key: TKey, value: TValue) {
        this.key = key;
        this.value = value;
    }
    
    getKey(): TKey {
        return this.key;
    }
    
    getValue(): TValue {
        return this.value;
    }
}

1.6 泛型参数默认值

TypeScript 允许为泛型参数指定默认类型。

typescript 复制代码
class DefaultGeneric<T = string> {
    private value: T;
    
    setValue(value: T) {
        this.value = value;
    }
    
    getValue(): T {
        return this.value;
    }
}

let defaultGeneric = new DefaultGeneric(); // T 默认为 string
let explicitGeneric = new DefaultGeneric<number>(); // 显式指定 T 为 number

1.7 泛型条件约束

结合条件类型,我们可以创建更加灵活的泛型约束。

typescript 复制代码
// 只有当 T 是 string 或 number 时才允许
type StringOrNumberOnly<T> = T extends string | number ? T : never;

function processValue<T>(value: StringOrNumberOnly<T>): StringOrNumberOnly<T> {
    return value;
}

processValue("hello"); // OK
processValue(42); // OK
// processValue(true); // Error: Type 'boolean' does not satisfy the constraint 'never'

二、条件类型和映射类型

2.1 条件类型基础

条件类型允许我们在类型层面进行条件判断,这是 TypeScript 类型系统的强大功能。

typescript 复制代码
// 基本条件类型
type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

// 更实用的例子
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;

interface Email {
    message: string;
}

interface Dog {
    bark(): void;
}

type EmailMessageContents = MessageOf<Email>; // string
type DogMessageContents = MessageOf<Dog>; // never

2.2 分配条件类型

当条件类型的检查类型是裸类型参数(naked type parameter)时,它会在联合类型上进行分配。

typescript 复制代码
type ToArray<Type> = Type extends any ? Type[] : never;

type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]

// 如果想阻止这种行为,可以用方括号包裹类型
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

type StrArrOrNumArr2 = ToArrayNonDist<string | number>; // (string | number)[]

2.3 infer 关键字

infer 关键字允许我们在条件类型中推断类型变量。

typescript 复制代码
// 推断函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

type Func = () => number;
type Result = ReturnType<Func>; // number

// 推断数组元素类型
type ElementType<T> = T extends (infer U)[] ? U : T;

type Arr = ElementType<string[]>; // string
type NotArr = ElementType<string>; // string

// 推断 Promise 的值类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type PromiseValue = UnwrapPromise<Promise<string>>; // string

2.4 预定义的条件类型

TypeScript 内置了一些有用的条件类型:

typescript 复制代码
// Exclude<UnionType, ExcludedMembers> - 从联合类型中排除某些成员
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

// Extract<Type, Union> - 从联合类型中提取某些成员
type T3 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T4 = Extract<string | number | boolean, boolean | number>; // number | boolean

// NonNullable<Type> - 从类型中排除 null 和 undefined
type T5 = NonNullable<string | number | undefined>; // string | number
type T6 = NonNullable<string[] | null | undefined>; // string[]

// Parameters<Type> - 获取函数参数类型
type T7 = Parameters<() => string>; // []
type T8 = Parameters<(s: string) => void>; // [string]

// ConstructorParameters<Type> - 获取构造函数参数类型
class Person {
    constructor(public name: string, public age: number) {}
}

type T9 = ConstructorParameters<typeof Person>; // [string, number]

// InstanceType<Type> - 获取构造函数实例类型
type T10 = InstanceType<typeof Person>; // Person

// Required<Type> - 将所有属性设为必需
interface Props {
    a?: number;
    b?: string;
}

type T11 = Required<Props>; // { a: number; b: string; }

// Partial<Type> - 将所有属性设为可选
type T12 = Partial<Props>; // { a?: number; b?: string; }

// Readonly<Type> - 将所有属性设为只读
type T13 = Readonly<Props>; // { readonly a?: number; readonly b?: string; }

// Pick<Type, Keys> - 从类型中选择特定属性
type T14 = Pick<Props, "a">; // { a?: number; }

// Omit<Type, Keys> - 从类型中省略特定属性
type T15 = Omit<Props, "a">; // { b?: string; }

// Record<Keys, Type> - 创建属性为 Keys,值为 Type 的对象类型
type T16 = Record<'x' | 'y', number>; // { x: number; y: number; }

2.5 映射类型

映射类型是一种从旧类型创建新类型的泛型类型,它使用 PropertyKey 的联合来遍历键以创建类型:

typescript 复制代码
// 基本映射类型
type OptionsFlags<Type> = {
    [Property in keyof Type]: boolean;
};

type FeatureFlags = {
    darkMode: () => void;
    newUserProfile: () => void;
};

type FeatureOptions = OptionsFlags<FeatureFlags>;
// {
//   darkMode: boolean;
//   newUserProfile: boolean;
// }

// 使用 readonly 和 ? 修饰符
type CreateMutable<Type> = {
    -readonly [Property in keyof Type]: Type[Property];
};

type LockedAccount = {
    readonly id: string;
    readonly name: string;
};

type UnlockedAccount = CreateMutable<LockedAccount>;
// { id: string; name: string; }

type Concrete<Type> = {
    [Property in keyof Type]-?: Type[Property];
};

type MaybeUser = {
    id: string;
    name?: string;
    age?: number;
};

type User = Concrete<MaybeUser>;
// { id: string; name: string; age: number; }

2.6 Key Remapping via as

TypeScript 4.1 引入了 key remapping,允许我们在映射类型中转换键名:

typescript 复制代码
type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};

interface Person {
    name: string;
    age: number;
    location: string;
}

type LazyPerson = Getters<Person>;
// {
//   getName: () => string;
//   getAge: () => number;
//   getLocation: () => string;
// }

// 通过模板字面量类型过滤键
type RemoveKindField<Type> = {
    [Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};

interface Circle {
    kind: "circle";
    radius: number;
}

type KindlessCircle = RemoveKindField<Circle>;
// { radius: number; }

2.7 深层映射类型

创建深层映射类型来处理嵌套对象:

typescript 复制代码
// 深度 Partial
type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

type NestedObject = {
    a: {
        b: {
            c: number;
        };
        d: string;
    };
    e: boolean;
};

type PartialNested = DeepPartial<NestedObject>;
// {
//   a?: {
//     b?: {
//       c?: number;
//     };
//     d?: string;
//   };
//   e?: boolean;
// }

// 深度 Required
type DeepRequired<T> = {
    [P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
};

三、装饰器模式(Decorator Pattern)

3.1 装饰器基础

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

注意:装饰器目前还是实验性特性,需要在 tsconfig.json 中启用:

json 复制代码
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

3.2 类装饰器

类装饰器应用于类构造函数,可以用来监视、修改或替换类定义。

typescript 复制代码
// 类装饰器函数
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;
    }
}

// 替换类构造函数的装饰器
function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

@classDecorator
class Greeter2 {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter2("world"));

3.3 方法装饰器

方法装饰器应用于方法的属性描述符,可以用来监视、修改或替换方法定义。

typescript 复制代码
function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = value;
    };
}

class Greeter3 {
    greeting: string;
    
    constructor(message: string) {
        this.greeting = message;
    }
    
    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

3.4 访问器装饰器

访问器装饰器应用于访问器的属性描述符,可以用来监视、修改或替换访问器的定义。

typescript 复制代码
function configurable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.configurable = value;
    };
}

class Point {
    private _x: number;
    private _y: number;
    
    constructor(x: number, y: number) {
        this._x = x;
        this._y = y;
    }
    
    @configurable(false)
    get x() { return this._x; }
    
    @configurable(false)
    get y() { return this._y; }
}

3.5 属性装饰器

属性装饰器应用于类的属性声明,不能用来改变一个属性的声明或实现,但可以用来监视一个属性在类中的访问。

typescript 复制代码
function format(formatString: string) {
    return function (target: any, propertyKey: string) {
        // 存储格式信息,可以在其他地方使用
        let value: string;
        
        const descriptor: PropertyDescriptor = {
            get: function () {
                return value;
            },
            set: function (newVal) {
                value = formatString.replace('{0}', newVal);
            },
            enumerable: true,
            configurable: true
        };
        
        Object.defineProperty(target, propertyKey, descriptor);
    }
}

class Greeter4 {
    @format("Hello, {0}")
    greeting: string;
    
    constructor(message: string) {
        this.greeting = message;
    }
}

const greeter = new Greeter4("World");
console.log(greeter.greeting); // "Hello, World"

3.6 参数装饰器

参数装饰器应用于类构造函数或方法的参数,参数装饰器只能用来监视一个方法的参数是否被传入。

typescript 复制代码
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
    // 可以记录哪些参数是必需的
    console.log(`Parameter ${parameterIndex} is required for method ${propertyKey.toString()}`);
}

class Greeter5 {
    greeting: string;
    
    constructor(message: string) {
        this.greeting = message;
    }
    
    greet(@required name: string) {
        return "Hello " + name + ", " + this.greeting;
    }
}

3.7 装饰器工厂

装饰器工厂是可以传参的装饰器,返回一个装饰器函数。

typescript 复制代码
function log(level: string) {
    return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
        const method = descriptor.value;
        
        descriptor.value = function (...args: any[]) {
            console.log(`[${level}] Calling ${propertyName} with`, args);
            const result = method.apply(this, args);
            console.log(`[${level}] Method ${propertyName} returned`, result);
            return result;
        }
    }
}

class Calculator {
    @log('DEBUG')
    add(a: number, b: number) {
        return a + b;
    }
    
    @log('INFO')
    multiply(a: number, b: number) {
        return a * b;
    }
}

const calc = new Calculator();
calc.add(2, 3); // [DEBUG] Calling add with [2, 3]
                // [DEBUG] Method add returned 5

3.8 复合装饰器

多个装饰器可以应用在一个声明上,它们会按照特定顺序求值和应用。

typescript 复制代码
function first() {
    console.log("first(): factory evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("first(): called");
    }
}

function second() {
    console.log("second(): factory evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("second(): called");
    }
}

class Example {
    @first()
    @second()
    method() {}
}

// 输出顺序:
// first(): factory evaluated
// second(): factory evaluated
// second(): called
// first(): called

四、模块声明和类型增强

4.1 模块声明基础

TypeScript 允许你为现有的 JavaScript 库编写声明文件,以便在 TypeScript 项目中获得类型安全。

typescript 复制代码
// 声明全局变量
declare var $: JQueryStatic;

// 声明全局函数
declare function greet(name: string): void;

// 声明全局对象
declare namespace MyApp {
    interface Config {
        apiUrl: string;
        timeout: number;
    }
    
    function init(config: Config): void;
}

4.2 模块声明

当你需要为外部库提供类型信息时,可以创建声明文件:

typescript 复制代码
// myLibrary.d.ts
declare module "myLibrary" {
    export interface Options {
        timeout?: number;
        retries?: number;
    }
    
    export function request(url: string, options?: Options): Promise<any>;
    export function cancel(token: any): void;
}

// 使用
import { request, Options } from "myLibrary";

const options: Options = {
    timeout: 5000,
    retries: 3
};

request("https://api.example.com/data", options);

4.3 通配符模块声明

当你需要为一组模块提供声明时,可以使用通配符:

typescript 复制代码
// 为所有 .css 文件提供声明
declare module "*.css" {
    const content: { [className: string]: string };
    export default content;
}

// 为所有图片文件提供声明
declare module "*.png" {
    const value: string;
    export default value;
}

declare module "*.jpg" {
    const value: string;
    export default value;
}

declare module "*.svg" {
    const value: string;
    export default value;
}

4.4 类型增强(Augmenting)

TypeScript 允许你扩展现有类型,添加新的属性或方法。

typescript 复制代码
// 扩展全局 Window 接口
declare global {
    interface Window {
        myCustomProperty: string;
        myCustomFunction(): void;
    }
}

// 扩展已有接口
interface Array<T> {
    groupBy<U>(keySelector: (item: T) => U): Map<U, T[]>;
}

// 实现扩展的方法
Array.prototype.groupBy = function<T, U>(keySelector: (item: T) => U): Map<U, T[]> {
    const map = new Map<U, T[]>();
    this.forEach(item => {
        const key = keySelector(item);
        const collection = map.get(key);
        if (!collection) {
            map.set(key, [item]);
        } else {
            collection.push(item);
        }
    });
    return map;
};

4.5 模块增强(Module Augmentation)

你可以扩展现有模块的类型:

typescript 复制代码
// observable.d.ts
export declare class Observable<T> {
    subscribe(observer: (value: T) => void): void;
}

// 扩展 Observable 模块
import { Observable } from "./observable";

declare module "./observable" {
    interface Observable<T> {
        map<R>(project: (value: T) => R): Observable<R>;
        filter(predicate: (value: T) => boolean): Observable<T>;
    }
}

// 实现扩展的方法
Observable.prototype.map = function(project) {
    // 实现 map 方法
    return new Observable(/* ... */);
};

Observable.prototype.filter = function(predicate) {
    // 实现 filter 方法
    return new Observable(/* ... */);
};

4.6 声明合并(Declaration Merging)

TypeScript 允许将多个同名声明合并为一个声明:

typescript 复制代码
// 接口合并
interface Box {
    height: number;
    width: number;
}

interface Box {
    scale: number;
}

let box: Box = {height: 5, width: 6, scale: 10};

// 命名空间合并
namespace Animals {
    export class Zebra { }
}

namespace Animals {
    export interface Legged { numberOfLegs: number; }
    export class Dog { }
}

// 合并后的 Animals 包含 Zebra, Legged, Dog

五、类型推导和类型守卫

5.1 类型推导基础

TypeScript 编译器会根据赋值表达式和其他上下文自动推断类型。

typescript 复制代码
// 基础类型推导
let x = 3; // 推导为 number
let y = [0, 1, null]; // 推导为 (number | null)[]

// 最佳通用类型
let zoo = [new Rhino(), new Elephant(), new Snake()];
// 推导为 (Rhino | Elephant | Snake)[]

// 上下文类型推导
window.onmousedown = function(mouseEvent) {
    console.log(mouseEvent.button); // 正确,推导为 MouseEvent
    // console.log(mouseEvent.foo); // 错误,MouseEvent 没有 foo 属性
};

5.2 控制流类型分析

TypeScript 3.7 引入了更精确的控制流类型分析:

typescript 复制代码
function example(x: string | number | boolean) {
    if (typeof x === "string") {
        x; // 推导为 string
        x.toUpperCase();
    } else if (typeof x === "number") {
        x; // 推导为 number
        x.toFixed();
    } else {
        x; // 推导为 boolean
        x.valueOf();
    }
}

// 数组类型守卫
function isStringArray(arr: unknown[]): arr is string[] {
    return arr.every(item => typeof item === "string");
}

function processArray(arr: (string | number)[]) {
    if (isStringArray(arr)) {
        arr; // 推导为 string[]
        arr.map(str => str.toUpperCase());
    } else {
        // 处理混合数组
    }
}

5.3 类型守卫(Type Guards)

类型守卫是一些表达式,它们在运行时检查以确保在某个作用域内的类型。

typescript 复制代码
// typeof 类型守卫
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return " ".repeat(padding) + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}

// instanceof 类型守卫
class Bird {
    fly() {}
    layEggs() {}
}

class Fish {
    swim() {}
    layEggs() {}
}

function move(animal: Bird | Fish) {
    if (animal instanceof Bird) {
        animal.fly();
    } else {
        animal.swim();
    }
}

// in 操作符类型守卫
interface Car {
    engine: string;
}

interface Bicycle {
    pedals: number;
}

function inspectVehicle(vehicle: Car | Bicycle) {
    if ("engine" in vehicle) {
        vehicle; // 推导为 Car
        console.log(vehicle.engine);
    } else {
        vehicle; // 推导为 Bicycle
        console.log(vehicle.pedals);
    }
}

5.4 自定义类型守卫

你可以创建自己的类型守卫函数来细化类型:

typescript 复制代码
// 用户定义的类型守卫
function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

function getSmallPet(): Fish | Bird {
    // 返回 Fish 或 Bird 的实现
    return Math.random() > 0.5 ? new Fish() : new Bird();
}

let pet = getSmallPet();

if (isFish(pet)) {
    pet.swim();
} else {
    pet.fly();
}

// 更复杂的类型守卫
interface Admin {
    name: string;
    privileges: string[];
}

interface Employee {
    name: string;
    startDate: Date;
}

type UnknownEmployee = Employee | Admin;

function isAdmin(employee: UnknownEmployee): employee is Admin {
    return "privileges" in employee;
}

function printEmployeeInformation(emp: UnknownEmployee) {
    console.log("Name: " + emp.name);
    
    if (isAdmin(emp)) {
        console.log("Privileges: " + emp.privileges.join(", "));
    } else {
        console.log("Start Date: " + emp.startDate);
    }
}

5.5 可辨识联合(Discriminated Unions)

通过共同的可辨识字段来区分不同类型的联合类型:

typescript 复制代码
interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle;

function area(s: Shape) {
    switch (s.kind) {
        case "square":
            return s.size * s.size;
        case "rectangle":
            return s.width * s.height;
        case "circle":
            return Math.PI * s.radius ** 2;
        default:
            // 穷尽性检查
            const _exhaustiveCheck: never = s;
            return _exhaustiveCheck;
    }
}

// 添加新形状时,编译器会报错,提醒你处理新情况
interface Triangle {
    kind: "triangle";
    base: number;
    height: number;
}

// type Shape = Square | Rectangle | Circle | Triangle;
// 上述代码会导致编译错误,因为 area 函数没有处理 triangle 情况

5.6 类型谓词(Type Predicates)

类型谓词是返回类型为 type is TypeName 的函数,用于类型守卫:

typescript 复制代码
// 数组类型谓词
function isStringArray(value: unknown): value is string[] {
    return Array.isArray(value) && value.every(item => typeof item === "string");
}

// 对象类型谓词
interface User {
    id: number;
    name: string;
    email: string;
}

function isUser(obj: unknown): obj is User {
    return (
        typeof obj === "object" &&
        obj !== null &&
        "id" in obj &&
        "name" in obj &&
        "email" in obj &&
        typeof (obj as User).id === "number" &&
        typeof (obj as User).name === "string" &&
        typeof (obj as User).email === "string"
    );
}

// 使用类型谓词
function processData(data: unknown) {
    if (isStringArray(data)) {
        // data 被推导为 string[]
        data.map(str => str.toUpperCase());
    } else if (isUser(data)) {
        // data 被推导为 User
        console.log(`User: ${data.name} (${data.email})`);
    } else {
        console.log("Unknown data type");
    }
}

5.7 类型断言(Type Assertions)

虽然不是类型推导的一部分,但类型断言是 TypeScript 中重要的类型操作:

typescript 复制代码
// 尖括号语法
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;

// as 语法(推荐)
let someValue2: unknown = "this is a string";
let strLength2: number = (someValue2 as string).length;

// 非空断言操作符
function fixed(name: string | null): string {
    function postprocess(name: string) {
        return name.charAt(0).toUpperCase() + name.substr(1);
    }
    
    // name 可能为 null,但我们确定它不为 null
    return postprocess(name!);
}

// 类型断言 vs 类型守卫
interface Cat {
    meow(): void;
}

interface Dog {
    bark(): void;
}

function handleAnimal(animal: Cat | Dog) {
    // 类型断言(不安全)
    (animal as Cat).meow(); // 如果 animal 是 Dog,会运行时报错
    
    // 类型守卫(安全)
    if ("meow" in animal) {
        animal.meow(); // 安全调用
    }
}

总结

TypeScript 的高级特性为我们提供了强大的类型系统和编程能力:

  1. 泛型编程让我们能够编写高度可重用且类型安全的代码
  2. 条件类型和映射类型提供了强大的类型变换能力
  3. 装饰器模式允许我们以声明式的方式增强类和成员的行为
  4. 模块声明和类型增强使我们能够为现有库添加类型信息并扩展类型
  5. 类型推导和类型守卫让 TypeScript 能够在运行时保持类型安全

掌握这些高级特性不仅能提高代码质量和开发效率,还能让我们写出更加健壮和易于维护的应用程序。随着 TypeScript 生态的不断发展,这些特性将在现代前端开发中发挥越来越重要的作用。

相关推荐
少卿2 小时前
React Compiler 完全指南:自动化性能优化的未来
前端·javascript
广州华水科技2 小时前
水库变形监测推荐:2025年单北斗GNSS变形监测系统TOP5,助力基础设施安全
前端
广州华水科技2 小时前
北斗GNSS变形监测一体机在基础设施安全中的应用与优势
前端
七淮2 小时前
umi4暗黑模式设置
前端
8***B2 小时前
前端路由权限控制,动态路由生成
前端
军军3603 小时前
从图片到点阵:用JavaScript重现复古数码点阵艺术图
前端·javascript
znhy@1233 小时前
Vue基础知识(一)
前端·javascript·vue.js
terminal0073 小时前
浅谈useRef的使用和渲染机制
前端·react.js·面试
我的小月月3 小时前
🔥 手把手教你实现前端邮件预览功能
前端·vue.js
陈佬昔没带相机3 小时前
MiniMax M2 + Trae 编码评测:能否与 Claude 4.5 扳手腕?
前端·人工智能·ai编程