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 生态的不断发展,这些特性将在现代前端开发中发挥越来越重要的作用。

相关推荐
用户47949283569155 分钟前
我只是给Typescript提个 typo PR,为什么还要签协议?
前端·后端·开源
程序员爱钓鱼26 分钟前
Next.js SSR 项目生产部署全攻略
前端·next.js·trae
程序员爱钓鱼27 分钟前
使用Git 实现Hugo热更新部署方案(零停机、自动上线)
前端·next.js·trae
颜颜yan_43 分钟前
DevUI + Vue 3 入门实战教程:从零构建AI对话应用
前端·vue.js·人工智能
ttod_qzstudio1 小时前
Vue 3 + TypeScript 严格模式下的 Performance.now() 实践:构建高性能前端应用
typescript·performance
国服第二切图仔2 小时前
DevUI Design中后台产品开源前端解决方案之Carousel 走马灯组件使用指南
前端·开源
无限大62 小时前
为什么浏览器能看懂网页代码?——从HTML到渲染引擎的奇幻之旅
前端
福尔摩斯张2 小时前
Linux信号捕捉特性详解:从基础到高级实践(超详细)
linux·运维·服务器·c语言·前端·驱动开发·microsoft
2401_860319522 小时前
DevUI组件库实战:从入门到企业级应用的深度探索 ,如何快速安装DevUI
前端·前端框架
cc蒲公英2 小时前
javascript有哪些内置对象
java·前端·javascript