You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中实现泛型策略模式并解决类型编译问题

解决TypeScript策略模式中的类型匹配问题

原模型代码

enum MyType {
    CHILD_X = "CHILD_X",
    CHILD_Y = "CHILD_Y"
}

abstract class ParentObject {
    readonly type: MyType;
    p: number;
    constructor(type: MyType, p: number) {
        this.type = type;
        this.p = p;
    } 

    public abstract returnMyself(): ParentObject;
}

class ChildXObject extends ParentObject {
    x: string;
    constructor(p: number, x: string) {
        super(MyType.CHILD_X, p);
        this.x = x;
    } 

    public returnMyself() {
        return this;
    }
}

class ChildYObject extends ParentObject {
    y: string;
    constructor(p: number, y: string) {
        super(MyType.CHILD_Y, p);
        this.y = y;
    } 

    public returnMyself(): ChildYObject {
        return this;
    }
}

遇到的类型错误

尝试1:类型交集错误

type PrintTypeToClass = {
    CHILD_X: ChildXObject
    CHILD_Y: ChildYObject
}

const RENDERERS: {[key in MyType]: (p: PrintTypeToClass[key]) => void} = {
    [MyType.CHILD_X]: function(x: ChildXObject): void {
        console.log(x.p);
        console.log(x.x);
    },
    [MyType.CHILD_Y]: function(y: ChildYObject): void {
        console.log(y.p);
        console.log(y.y);
    }
};

type Objs = ChildXObject | ChildYObject
const listOfObjects: Objs[] = [
    new ChildXObject(0, ""),
    new ChildYObject(0, "")
];

listOfObjects.map(obj => {
    const fn = RENDERERS[obj.type];
    fn(obj); // Argument of type 'Objs' is not assignable to parameter of type 'ChildXObject & ChildYObject'.
})

报错信息:Argument of type 'Objs' is not assignable to parameter of type 'ChildXObject & ChildYObject'

尝试2:泛型函数不兼容错误

const RENDERERS: {[key in MyType]: <T extends ParentObject>(p: T) => void} = {
    // Type of computed property's value is '<T extends ParentObject>(x: ChildXObject) => void', which is not assignable to type '<T extends ParentObject>(p: T) => void'.
    [MyType.CHILD_X]: function(x: ChildXObject): void {
        console.log(x.p);
        console.log(x.x);
    },
    [MyType.CHILD_Y]: function(y: ChildYObject): void {
        console.log(y.p);
        console.log(y.y);
    }
};

const listOfObjects: ParentObject[] = [
    new ChildXObject(0, ""),
    new ChildYObject(0, "")
];

listOfObjects.map(obj => {
    const fn = RENDERERS[obj.type];
    fn(obj);
})

报错信息:Type of computed property's value is '<T extends ParentObject>(x: ChildXObject) => void', which is not assignable to type '<T extends ParentObject>(p: T) => void'

解决方案

方案1:利用泛型函数关联类型

通过泛型函数明确对象类型与type字段的对应关系,让TypeScript正确推断匹配的渲染函数:

type PrintTypeToClass = {
    [MyType.CHILD_X]: ChildXObject;
    [MyType.CHILD_Y]: ChildYObject;
};

const RENDERERS: { [K in MyType]: (obj: PrintTypeToClass[K]) => void } = {
    [MyType.CHILD_X]: (obj) => {
        console.log(obj.p, obj.x);
    },
    [MyType.CHILD_Y]: (obj) => {
        console.log(obj.p, obj.y);
    }
};

type Objs = PrintTypeToClass[MyType];
const listOfObjects: Objs[] = [
    new ChildXObject(0, "x"),
    new ChildYObject(0, "y")
];

// 泛型函数确保类型严格匹配
function render<K extends MyType>(obj: PrintTypeToClass[K]) {
    RENDERERS[obj.type](obj);
}

listOfObjects.forEach(render);

方案2:使用类型守卫显式推断

自定义类型守卫函数,在运行时判断对象具体类型,从而匹配对应渲染逻辑:

// 类型守卫函数:判断对象是否为ChildXObject
function isChildX(obj: ParentObject): obj is ChildXObject {
    return obj.type === MyType.CHILD_X;
}

// 类型守卫函数:判断对象是否为ChildYObject
function isChildY(obj: ParentObject): obj is ChildYObject {
    return obj.type === MyType.CHILD_Y;
}

// 定义渲染器(同尝试1的RENDERERS)
type PrintTypeToClass = {
    CHILD_X: ChildXObject
    CHILD_Y: ChildYObject
}

const RENDERERS: {[key in MyType]: (p: PrintTypeToClass[key]) => void} = {
    [MyType.CHILD_X]: function(x: ChildXObject): void {
        console.log(x.p);
        console.log(x.x);
    },
    [MyType.CHILD_Y]: function(y: ChildYObject): void {
        console.log(y.p);
        console.log(y.y);
    }
};

const listOfObjects: ParentObject[] = [
    new ChildXObject(0, ""),
    new ChildYObject(0, "")
];

listOfObjects.forEach(obj => {
    if (isChildX(obj)) {
        RENDERERS[MyType.CHILD_X](obj);
    } else if (isChildY(obj)) {
        RENDERERS[MyType.CHILD_Y](obj);
    }
});

方案3:类型断言快速修复(简洁场景)

若能确保类型匹配的准确性,可使用类型断言快速绕过编译错误:

type PrintTypeToClass = {
    CHILD_X: ChildXObject
    CHILD_Y: ChildYObject
}

const RENDERERS: {[key in MyType]: (p: PrintTypeToClass[key]) => void} = {
    [MyType.CHILD_X]: function(x: ChildXObject): void {
        console.log(x.p);
        console.log(x.x);
    },
    [MyType.CHILD_Y]: function(y: ChildYObject): void {
        console.log(y.p);
        console.log(y.y);
    }
};

type Objs = ChildXObject | ChildYObject
const listOfObjects: Objs[] = [
    new ChildXObject(0, ""),
    new ChildYObject(0, "")
];

listOfObjects.map(obj => {
    const fn = RENDERERS[obj.type];
    // 断言obj为当前type对应的具体类型
    fn(obj as PrintTypeToClass[typeof obj.type]);
});

内容的提问来源于stack exchange,提问作者spxcxlxxs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 03:05:56