Типоскрипт, повторяющий объект с типом объединения

#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 секунд! хахаха