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

TypeScript中复用属性名不同的相似对象组件的类型处理

解决方案

针对组件复用、类型定义及扩展需求,这里提供几种实用方案:

方案一:组件内部做属性映射(对调用方无侵入)

无需调用方修改传入对象,组件内部根据variant字段将不同属性名统一为通用名称,避免类型错误,同时方便后续扩展。

type Obj1_Type = {
    id: number;
    packageId: number;
    value: string;
};

type Obj2_Type = {
    id: number;
    otherId: number;
    value: string;
};

type ComponentType =
    | { variant: "obj1"; obj: Obj1_Type }
    | { variant: "obj2"; obj: Obj2_Type };

const MyComponent = (item: ComponentType) => {
    // 根据variant统一获取目标属性
    const targetId = item.variant === "obj1" ? item.obj.packageId : item.obj.otherId;
    return <> {targetId} </>;
};

// 新增类型时,仅需扩展ComponentType和映射逻辑
type Obj3_Type = { id: number; customId: number; value: string };
type ComponentTypeExtended = ComponentType | { variant: "obj3"; obj: Obj3_Type };

const MyComponentExtended = (item: ComponentTypeExtended) => {
    let targetId: number;
    switch(item.variant) {
        case "obj1": targetId = item.obj.packageId; break;
        case "obj2": targetId = item.obj.otherId; break;
        case "obj3": targetId = item.obj.customId; break;
        default: throw new Error("Unknown variant");
    }
    return <> {targetId} </>;
};

方案二:定义通用类型,调用方传入标准化对象

让组件逻辑更简洁,先定义通用标准类型,要求调用方传入符合该类型的对象,或提前将原有对象转换为标准格式。

// 定义通用标准类型
type StandardObj = {
    id: number;
    targetId: number; // 统一属性名
    value: string;
};

// 组件直接接收标准类型,无分支逻辑
const MyComponent = (obj: StandardObj) => {
    return <> {obj.targetId} </>;
};

// 调用方转换原有对象
const obj1: Obj1_Type = { id: 1, packageId: 100, value: "test" };
MyComponent({ ...obj1, targetId: obj1.packageId });

const obj2: Obj2_Type = { id: 2, otherId: 200, value: "demo" };
MyComponent({ ...obj2, targetId: obj2.otherId });

// 新增类型时,仅需转换为StandardObj即可,组件无需修改
type Obj3_Type = { id: number; customId: number; value: string };
const obj3: Obj3_Type = { id:3, customId:300, value:"new" };
MyComponent({ ...obj3, targetId: obj3.customId });

方案三:泛型+类型映射实现灵活扩展

通过类型映射定义不同variant对应的属性名,结合泛型让组件类型自动推导,后续新增类型仅需扩展映射表,无需修改组件逻辑。

type Obj1_Type = { id: number; packageId: number; value: string };
type Obj2_Type = { id: number; otherId: number; value: string };
type Obj3_Type = { id: number; customId: number; value: string };

// 定义variant到属性名的映射表
type VariantToProp = {
    obj1: "packageId";
    obj2: "otherId";
    obj3: "customId";
};

// 定义组件通用类型
type ComponentType<T extends keyof VariantToProp> = {
    variant: T;
    obj: {
        id: number;
        [K in VariantToProp[T]]: number;
        value: string;
    };
};

// 组件使用泛型自动推导属性名
const MyComponent = <T extends keyof VariantToProp>(item: ComponentType<T>) => {
    const propName = VariantToProp[item.variant];
    return <> {item.obj[propName as keyof typeof item.obj]} </>;
};

// 调用示例
MyComponent({ variant: "obj1", obj: { id:1, packageId:100, value:"test" } });
MyComponent({ variant: "obj2", obj: { id:2, otherId:200, value:"demo" } });
MyComponent({ variant: "obj3", obj: { id:3, customId:300, value:"new" } });

方案对比

  • 方案一:适合不想改动调用方代码的场景,逻辑集中在组件内部,扩展时修改组件即可。
  • 方案二:组件逻辑最简洁,转换工作交给调用方,适合需要强制标准化的场景。
  • 方案三:类型约束最严格,扩展性最强,新增类型仅需更新VariantToProp映射表,组件逻辑无需修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 02:15:37