Почему эти два типа AB и CD взаимно назначаются в TypeScript?

Почему два типа, установленные следующими интерфейсами, одинаковы?

interface AB {
    a?: string;
    b?: string;
    c?: string;
}

interface CD {
    c?: string;
    d?: string;
    
    a?: string;
}

(пример, показывающий, что они взаимоназначаемы, находится здесь)

Конечно, они имеют общие свойства a и c, но не b и d.

Это не имеет ничего общего с условными типами; ваша демонстрация такая же, как этот пример без них. Действительно, демонстрация такая же, как этот пример без занятий. Вероятно, ваш вопрос: «Почему AB и CD взаимно назначаются в TypeScript»? На это есть ответ, но не могли бы вы отредактировать вопрос, чтобы он был минимально воспроизводимым примером без ссылки на условные типы и, возможно, даже без ссылки на классы? Тогда мы сможем ответить на вопрос более прямо. Если вы спрашиваете не об этом, пожалуйста, отредактируйте, чтобы внести ясность.

jcalz 15.05.2024 18:12

TS необоснован в отношении необязательных свойств. См. этот комментарий и этот комментарий. Было бы безопаснее, но очень неприятно, если бы вы не могли писать const x = {a: 0}; const y: {a: number, b?: string} = x. ТС позволяет такое. Если вы хотите, чтобы типы были несовместимы, вы должны убедиться, что они различаются не только отсутствием необязательного свойства. Это полностью решает вопрос или я что-то упускаю?

jcalz 15.05.2024 20:45

Да, это полностью отвечает на мой вопрос. Если вы напишете ответ, я приму его. Спасибо!

daflodedeing 16.05.2024 08:15
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
3
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К лучшему или худшему, система типов 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, вы не увидите проблем с таким перекрестным присвоением.

Итак, он ведет себя так, как задумано.

Детская площадка, ссылка на код

Другие вопросы по теме