ZetCode

TypeScript Mixins

最后修改时间:2025年3月3日

TypeScript 中的 Mixins 是可重用的代码模式,允许将多个类或对象组合成一个类。它们支持组合而非继承,从而促进灵活且易于维护的代码。本教程将探讨 Mixin 语法、实现和实际示例。

基本 Mixin 语法

Mixin 使用扩展基类的函数来实现。本示例展示了一个简单的 Mixin 模式。

basic_mixin.ts
type Constructor = new (...args: any[]) => {};

function Timestamped<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        timestamp = Date.now();
    };
}

class User {
    constructor(public name: string) {}
}

const TimestampedUser = Timestamped(User);
const user = new TimestampedUser("Alice");
console.log(user.timestamp);  // Output: Current timestamp

Timestamped Mixin 为其扩展的任何类添加了 timestamp 属性。这促进了代码的重用,而无需继承。

多个 Mixins

可以组合多个 Mixins 来创建复杂的类。本示例演示了组合两个 Mixins。

multiple_mixins.ts
function Loggable<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        log(message: string) {
            console.log(`[LOG]: ${message}`);
        }
    };
}

class User {
    constructor(public name: string) {}
}

const LoggableTimestampedUser = Loggable(Timestamped(User));
const user = new LoggableTimestampedUser("Bob");
user.log("User created");  // Output: [LOG]: User created
console.log(user.timestamp);  // Output: Current timestamp

Loggable Mixin 添加了日志记录功能,而 Timestamped 添加了时间戳。两者都可以无缝组合。

带方法的 Mixin

Mixin 可以包含方法来扩展类的行为。本示例添加了一个计算年龄的方法。

mixin_with_methods.ts
function Aged<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        getAge(birthYear: number): number {
            return new Date().getFullYear() - birthYear;
        }
    };
}

class User {
    constructor(public name: string) {}
}

const AgedUser = Aged(User);
const user = new AgedUser("Charlie");
console.log(user.getAge(1990));  // Output: Age based on birth year

Aged Mixin 添加了一个 getAge 方法,根据用户的出生年份计算其年龄。

带属性的 Mixin

Mixin 也可以为类添加属性。本示例添加了一个 role 属性。

mixin_with_properties.ts
function RoleBased<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        role: string = "User";
    };
}

class User {
    constructor(public name: string) {}
}

const RoleBasedUser = RoleBased(User);
const user = new RoleBasedUser("Diana");
console.log(user.role);  // Output: User

RoleBased Mixin 添加了一个 role 属性,默认值为“User”。

带覆盖的 Mixin

Mixin 可以覆盖现有方法或属性。本示例覆盖了基类中的一个方法。

mixin_with_overrides.ts
function OverrideGreeting<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        greet() {
            return `Hello, ${this.name}!`;
        }
    };
}

class User {
    constructor(public name: string) {}
    greet() {
        return `Hi, ${this.name}!`;
    }
}

const OverrideUser = OverrideGreeting(User);
const user = new OverrideUser("Eve");
console.log(user.greet());  // Output: Hello, Eve!

OverrideGreeting Mixin 覆盖了基类中的 greet 方法,改变了其行为。

最佳实践

来源

TypeScript Mixins 文档

本教程通过实际示例介绍了 TypeScript Mixins。使用 Mixins 创建可重用且易于维护的代码模式。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 TypeScript 教程