Я пытаюсь вывести тип «данных» на основе значения «типа» поля, но, похоже, я делаю это неправильно... Я хочу использовать оператор пересечения, чтобы избежать множества строк условий.
См. код ниже:
interface IActivityNote {
type: "note";
data: {
title: string;
content?: string;
};
}
interface IActivityArchive {
type: "archive";
data: { reason: string };
}
type TActivityData = IActivityNote | IActivityArchive;
interface IActivityBase {
id: string;
ownerId: string;
}
type TActivity = IActivityBase & TActivityData;
interface IActivityServerBase {
id: string;
owner: string;
}
type TActivityServer = IActivityServerBase & TActivityData;
const mapToActivityServer = (activity: TActivity): TActivityServer => ({
id: activity.id,
owner: activity.ownerId,
type: activity.type,
data: activity.data
});
Почему TS не получает его сам по себе? Должен ли я помещать условие внутри функции, чтобы указать структуру данных на основе значения типа?
Воспроизведение здесь: https://codesandbox.io/s/typescript-infering-type-value-with-interface-intersection-svdgsd?file=/src/index.ts
В основном я хочу, чтобы тип был либо:
{
id: string
owner: string
type: 'note'
data: { title: string; content?: string }
}
// OR
{
id: string
owner: string
type: 'archive'
data: { reason: string }
}
Но используя тип интеллектуального пересечения, чтобы избежать дублирования всех типов объектов для каждого нового значения «типа» с другой структурой «данных», которую я хочу реализовать.
Не могли бы вы привести пример своего заявления? Я не уверен, что понимаю, что вы имеете в виду @kellys Редактировать: Если вы имеете в виду вот так: type TActivityServer = (IActivityServerBase & IActivityNote) | (IActivityServerBase & IActivityArchive)
, это не работает
Пожалуйста, редактировать вопрос, чтобы явно описать ошибку, с которой вы столкнулись, чтобы код представлял собой минимальный воспроизводимый пример.
Кажется, это известная ошибка, мс/ТС#33654. Я бы подумал, что "умная проверка типов союзов" и мс/ТС#36663 включили бы что-то подобное, но я думаю, что нет. Обходной путь выглядит как это. Это относится к вашему вопросу? Если да, то я могу написать ответ; если нет, то что мне не хватает?
@jcalz Ну да! Безопасность типа работает правильно в вашем примере, спасибо за подсказку;)
Это известная ошибка в TypeScript, см. Майкрософт/TypeScript#33654. До того, как TypeScript 3.5 представил более умная проверка типа объединения, это не могло работать, потому что компилятор не пытался связать тип, который он выводит для вашего вывода, с аннотированным возвращаемым типом. PR в Майкрософт/TypeScript#30779 изменил ситуацию, так что теперь есть некоторая попытка расширить типы объектов со свойствами объединения в объединения типов объектов, и PR в Майкрософт/TypeScript#36663, по-видимому, улучшает эту работу с пересечениями, но, по-видимому, ни одно из этих изменений недостаточно для заставить ваш код работать.
Пока не ясно, когда и будет ли исправлена эта ошибка. На данный момент обходной путь предложено в ms/TS#33654 заключается в распространении/деструктуризации, чтобы он действительно запускал «более умную проверку типов объединения». В вашем случае это может выглядеть так:
const mapToActivityServer = (activity: TActivity): TActivityServer => {
const { ownerId: owner, ...act } = activity;
return { ...act, owner }; // no error now
}
В настоящее время вы делаете союз, а затем пересекаетесь. Что, если вы сначала пересечете базу с данными, а затем сделаете из этого объединение?