#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 amp;amp; attributions.map((attribution: Family | Model ) => (
<tr>
{
attributionType === 'family' amp;amp; (
<React.Fragment>
<th>{attribution.family}</th>
<th>Family</th>
</React.Fragment>
)
}
{
attributionType === 'model' amp;amp; (
<React.Fragment>
<th>{attribution.model}</th>
<th>Model</th>
</React.Fragment>
)
}
</tr>
))}
);
}
Поскольку это объединение, я не могу получить доступ к любым другим членам объекта, которые не являются общими.
Я могу получить доступ cat
и age
, но не family
могу, lastYearFamily
и т. Д.
Я хочу, чтобы код был общим, если это возможно, и не имел отдельных компонентов для каждого типа атрибуции.
Комментарии:
1. Вы можете не делать
(attribution as Model).lastYearModel
или(attribution as Family).lastYearFamily
?
Ответ №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
}
}
Компилятор определит типы внутри if
s благодаря защите типов.
Ответ №2:
Обычно вы делаете это с помощью пользовательских защитников типов, которые состоят в приведении переменной в качестве предполагаемого типа и проверке наличия поля, уникального для этого типа, что позволяет сделать вывод о том, что значение переменной действительно относится к этому типу.
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;
}
})
Комментарии:
1. Мы опубликовали наши ответы с интервалом в 30 секунд! хахаха