Почему два типа, установленные следующими интерфейсами, одинаковы?
interface AB {
a?: string;
b?: string;
c?: string;
}
interface CD {
c?: string;
d?: string;
a?: string;
}
(пример, показывающий, что они взаимоназначаемы, находится здесь)
Конечно, они имеют общие свойства a и c, но не b и d.
TS необоснован в отношении необязательных свойств. См. этот комментарий и этот комментарий. Было бы безопаснее, но очень неприятно, если бы вы не могли писать const x = {a: 0}; const y: {a: number, b?: string} = x. ТС позволяет такое. Если вы хотите, чтобы типы были несовместимы, вы должны убедиться, что они различаются не только отсутствием необязательного свойства. Это полностью решает вопрос или я что-то упускаю?
Да, это полностью отвечает на мой вопрос. Если вы напишете ответ, я приму его. Спасибо!






К лучшему или худшему, система типов TypeScript не является полностью типизированной и надежной . Несмотря на то, что большая часть утилит TypeScript направлена на повышение безопасности типов, некоторые распространенные шаблоны кодирования нарушают эту безопасность; существует компромисс между безопасностью типов и выразительностью; TypeScript иногда ценит выразительность и удобство разработчика выше безопасности. См. Нецель дизайна TypeScript №5.
Одна из таких дыр в надежности связана с дополнительными свойствами . См. этот комментарий к microsoft/TypeScript#47731 и этот комментарий к microsoft/TypeScript#42479 для демонстрации.
Совершенно безопасно присвоить тип объекта с необязательным свойством типу, у которого отсутствует это свойство. Это просто обычное расширение типа, и TypeScript позволяет это:
let x: { a?: number, b: string } = { a: 1, b: "" };
let y: { b: string };
y = x; // okay
Но TypeScript также позволяет назначать тип объекта, у которого отсутствует свойство, типу с необязательным свойством с тем же ключом:
x = y; // okay?!
Технически это небезопасное сужение. Значение типа {b: string} может иметь любое свойство по ключу a (это потому, что типы TypeScript не являются «запечатанными» или «точными», см. «Расширить и указать только известные свойства?» для получения дополнительной информации):
const z = { a: "xyz", b: "" };
y = z; // okay
Это означает, что на самом деле небезопасно предполагать, что свойство a является либо undefined, либо string. Это приводит к возможным ошибкам во время выполнения:
x = y; // still okay, oops!
x.a?.toFixed(); // RUNTIME ERROR!
Тем не менее, на практике такое случается нечасто, и безопасная альтернатива была бы очень раздражающей, поскольку в общем случае большинство неизвестных свойств фактически отсутствуют. Люди постоянно пишут вот что:
const w = { b: "" };
x = w; // okay
function acceptX(x: { a?: number, b: string }) { }
acceptX(w); // okay
Все, что TypeScript знает о w, это то, что это тип {b: string}. Он не помнит, что в литерале инициализирующего объекта фактически отсутствовало свойство a. Если бы TypeScript жаловался каждый раз, когда не знал, присвоено ли неизвестное свойство необязательному, вышеописанное должно было бы привести к ошибке, и это свело бы людей с ума. Так что это разрешено.
Это подводит нас к
interface AB {
a?: string;
c?: string;
b?: string;
}
interface CD {
a?: string;
c?: string;
d?: string;
}
Эти типы являются взаимоназначаемыми, поскольку единственное, в чем они не совпадают, — это то, что у одного есть необязательное свойство, а у другого отсутствует. У них обоих есть необязательные свойства a и c типа string. Но у AB необязательное свойство b отсутствует в CD, а у CD необязательное свойство d отсутствует в AB. Ни одно из этих несоответствий не считается проблемой при назначении. И действительно, пока вы не начнете делать что-то с {b: 123, d: 456}, где соответствующие свойства присутствуют, но не string, вы не увидите проблем с таким перекрестным присвоением.
Итак, он ведет себя так, как задумано.
Это не имеет ничего общего с условными типами; ваша демонстрация такая же, как этот пример без них. Действительно, демонстрация такая же, как этот пример без занятий. Вероятно, ваш вопрос: «Почему
ABиCDвзаимно назначаются в TypeScript»? На это есть ответ, но не могли бы вы отредактировать вопрос, чтобы он был минимально воспроизводимым примером без ссылки на условные типы и, возможно, даже без ссылки на классы? Тогда мы сможем ответить на вопрос более прямо. Если вы спрашиваете не об этом, пожалуйста, отредактируйте, чтобы внести ясность.