混合類型(Mixin Types)是 TypeScript 中一種強大的類型系統特性,它允許一個類型既可以是函數又可以是對象。這種類型同時具備函數調用和對象屬性訪問的能力,為設計模式如裝飾器模式等提供了優雅的實現方式。
核心概念
混合類型通過將函數簽名與對象類型進行交叉(intersection)定義:
// 定義一個混合類型
interface MixedFunction {
(): void; // 函數調用簽名
property: string; // 對象屬性
method(): void; // 對象方法
}
// 使用示例
const myMixed: MixedFunction = (() => {
const func = (() => {
console.log("函數被調用");
}) as MixedFunction;
func.property = "混合屬性";
func.method = () => {
console.log("方法被調用");
};
return func;
})();
myMixed(); // 作為函數調用
console.log(myMixed.property); // 訪問屬性
myMixed.method(); // 調用方法
實現方式
1. 類型斷言方式
interface Counter {
(): number;
count: number;
reset(): void;
}
function createCounter(): Counter {
const counter = (() => {
counter.count++;
return counter.count;
}) as Counter;
counter.count = 0;
counter.reset = () => {
counter.count = 0;
};
return counter;
}
// 使用
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
counter.reset();
console.log(counter()); // 1
console.log(counter.count); // 1
2. 類實現方式
interface LoggerFunction {
(message: string): void;
level: string;
setLevel(level: string): void;
}
class Logger implements LoggerFunction {
public level: string = "info";
constructor() {
// 將實例作為函數調用時的處理
const instance = this as unknown as LoggerFunction;
const func = ((message: string) => {
console.log(`[${instance.level}] ${message}`);
}) as LoggerFunction;
// 複製屬性
Object.setPrototypeOf(func, this);
Object.assign(func, this);
return func as LoggerFunction;
}
setLevel(level: string): void {
this.level = level;
}
}
// 使用
const logger = new Logger() as LoggerFunction;
logger("這是一條日誌"); // [info] 這是一條日誌
logger.setLevel("error");
logger("這是一條錯誤日誌"); // [error] 這是一條錯誤日誌
實用的混合類型應用
1. 帶狀態的工具函數
interface CachedFunction<T extends (...args: any[]) => any> {
(...args: Parameters<T>): ReturnType<T>;
cache: Map<string, ReturnType<T>>;
clearCache(): void;
}
function createCachedFunction<T extends (...args: any[]) => any>(
fn: T
): CachedFunction<T> {
const cachedFn = ((...args: Parameters<T>) => {
const key = JSON.stringify(args);
if (cachedFn.cache.has(key)) {
console.log("使用緩存結果");
return cachedFn.cache.get(key);
}
const result = fn(...args);
cachedFn.cache.set(key, result);
return result;
}) as CachedFunction<T>;
cachedFn.cache = new Map();
cachedFn.clearCache = () => {
cachedFn.cache.clear();
};
return cachedFn;
}
// 使用
const expensiveCalculation = (a: number, b: number): number => {
console.log("執行復雜計算...");
return a * b;
};
const cachedCalc = createCachedFunction(expensiveCalculation);
console.log(cachedCalc(2, 3)); // 執行計算並緩存
console.log(cachedCalc(2, 3)); // 使用緩存
cachedCalc.clearCache();
2. 配置化的函數構造器
interface ConfigurableGreeter {
(name: string): string;
greeting: string;
setGreeting(greeting: string): void;
}
function createGreeter(initialGreeting: string = "Hello"): ConfigurableGreeter {
const greeter = ((name: string) => {
return `${greeter.greeting}, ${name}!`;
}) as ConfigurableGreeter;
greeter.greeting = initialGreeting;
greeter.setGreeting = (newGreeting: string) => {
greeter.greeting = newGreeting;
};
return greeter;
}
// 使用
const greeter = createGreeter();
console.log(greeter("Alice")); // Hello, Alice!
greeter.setGreeting("Hi");
console.log(greeter("Bob")); // Hi, Bob!
高級模式:多重混合
// 多重混合類型
interface AdvancedFunction {
(input: string): string;
// 配置功能
prefix: string;
setPrefix(prefix: string): void;
// 統計功能
callCount: number;
getCallCount(): number;
// 驗證功能
validator: (input: string) => boolean;
setValidator(validator: (input: string) => boolean): void;
}
function createAdvancedFunction(): AdvancedFunction {
const advancedFn = ((input: string) => {
advancedFn.callCount++;
if (advancedFn.validator && !advancedFn.validator(input)) {
throw new Error("輸入驗證失敗");
}
return `${advancedFn.prefix}${input}`;
}) as AdvancedFunction;
// 初始化屬性
advancedFn.prefix = ">> ";
advancedFn.callCount = 0;
advancedFn.validator = (input) => input.length > 0;
// 初始化方法
advancedFn.setPrefix = (prefix: string) => {
advancedFn.prefix = prefix;
};
advancedFn.getCallCount = () => advancedFn.callCount;
advancedFn.setValidator = (validator: (input: string) => boolean) => {
advancedFn.validator = validator;
};
return advancedFn;
}
// 使用
const processor = createAdvancedFunction();
console.log(processor("TypeScript")); // >> TypeScript
processor.setPrefix("處理: ");
console.log(processor("混合類型")); // 處理: 混合類型
console.log(processor.getCallCount()); // 2
最佳實踐
- 明確類型定義:使用接口明確定義混合類型的結構和約束
- 封裝構造邏輯:提供工廠函數來創建混合類型實例
- 保持單一職責:每個混合類型應該有明確的單一目的
- 文檔和註釋:為混合類型的使用提供清晰的文檔説明
混合類型是 TypeScript 類型系統靈活性的體現,合理使用可以創建出既功能強大又類型安全的API設計。