打字稿迭代具有联合类型的对象

时间:2021-05-27 16:52:03

标签: typescript

我需要遍历一个对象,该对象是两个接口的联合类型。

    interface Family {
      cat: string;
      age: string;
      family: string;
      lastYearFamily: string;
    }
    
    interface Model {
      cat: string;
      age: string;
      model: string;
      lastYearModel: string;
    }
    
    interface Props {
        attributionType: 'family' | 'model';
        attributions?: Family[] | Model[];
    }
    
    const RowComponent = ({
    attributionType,
    attributions
    }: props) =>{
    
       return (
          {attributions && attributions.map((attribution: Family | Model ) => (
                             <tr>
                                {
                                    attributionType === 'family' && (
                                        <React.Fragment>
                                            <th>{attribution.family}</th>
                                            <th>Family</th>
                                        </React.Fragment>
                                    )
                                } 
                                {
                                    attributionType === 'model' && (
                                        <React.Fragment>
                                            <th>{attribution.model}</th>
                                            <th>Model</th>
                                        </React.Fragment>
                                    )
                                } 
                             </tr>
                        ))}
    );
    
    }

由于这是一个联合,因此我无法访问该对象的任何其他不常见成员。

我可以访问 catage,但不能访问 familylastYearFamily

如果可能,我希望保持代码通用,而不是为每种归因类型设置单独的组件。

2 个答案:

答案 0 :(得分:1)

您并不是在向编译器暗示 'family' 接口中的字符串 Props 应该推断出属性上的 Family[]。您是在声明 attributionTypeattributions 没有相关性。

    // your code
    interface Props {
        attributionType: 'family' | 'model';
        attributions?: Family[] | Model[];
    }

为了向编译器暗示你想要这个,你可以在不同的接口中收集你需要的类型,然后才加入它们:

interface FamilyProp {
  attributionType: "family";
  attributions?: Family[];
}

interface ModelProp {
  attributionType: "model";
  attributions?: Model[];
}

type Props = ModelProp | FamilyProp;

function foo(bar: Props) {
    if (bar.attributionType === "model") {
        bar.attributions[0].lastYearModel; // compiles fine
    }
    if (bar.attributionType === "family") {
        bar.attributions[0].lastYearFamily; // compiles fine
    }
}

由于 Type Guard,编译器将推断 if 中的类型。

答案 1 :(得分:1)

您通常会使用自定义类型保护来执行此操作,它包括将变量转换为预期类型并检查是否存在该类型独有的字段,这允许您推断变量中的值确实属于该类型.

interface Family {
      cat: string;
      age: string;
      family: string;
      lastYearFamily: string;
}
    
interface Model {
      cat: string;
      age: string;
      model: string;
      lastYearModel: string;
}

const isFamily = (f: Family|Model): f is Family => {
    return (f as Family).family !== undefined
}

const isModel = (f: Family|Model): f is Model => {
    return (f as Model).model !== undefined
}

const x : (Family | Model)[] = [
    {cat: "x", age: "y", family: "z", lastYearFamily: "w"},
    {cat: "x", age: "y", model: "z", lastYearModel: "w"}
]

x.map(e => {
    if (isFamily(e)) {
        return e.family;
    } else {
        return e.model;
    }
})