我需要遍历一个对象,该对象是两个接口的联合类型。
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>
))}
);
}
由于这是一个联合,因此我无法访问该对象的任何其他不常见成员。
我可以访问 cat
和 age
,但不能访问 family
、lastYearFamily
等
如果可能,我希望保持代码通用,而不是为每种归因类型设置单独的组件。
答案 0 :(得分:1)
您并不是在向编译器暗示 'family'
接口中的字符串 Props
应该推断出属性上的 Family[]
。您是在声明 attributionType
与 attributions
没有相关性。
// 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;
}
})