Я не могу придумать «идеальное» решение для этого, которое работает при любых обстоятельствах. Большинство механизмов, которые убеждают компилятор выполнить требуемую проверку типов, также сопровождаются некоторым добавленным кодом времени выполнения (например, новым промежуточным присваиванием переменной или вызовом функции идентификации), который, как вы сказали, вам не нужен.
Одна проблема заключается в том, что TypeScript не имеет встроенных аннотаций типов. (См. microsoft / TypeScript # 7481 и microsoft / TypeScript # 13208 для обсуждения.) Вы хотели бы попросить компилятор проверить , что выражение {...}
относится к типу Person
, и его компилятор может пожаловаться, если его невозможно проверить. Ближайший оператор в TypeScript - это утверждение типа вида {...} as Person
. Но это сообщает компилятору, что выражение {...}
имеет тип Person
; Вы хотите спросить .
Даже если бы у нас был встроенный оператор аннотации, есть еще одна проблема: типы объектов в TypeScript не точны . (См. microsoft / TypeScript # 12936 для обсуждения.) Типы объектов в TypeScript: open , так как вы можете добавить к ним больше свойств, не нарушая совместимость. Если у вас есть объект типа Person
, вы знаете кое-что о его свойствах first
и last
, но вы действительно ничего не знаете о других свойствах. Тот факт, что определение Person
не упоминает свойство age
, не означает , что объект типа Person
не может иметь свойство age
. Вполне может быть такой интерфейс:
interface AgedPerson extends Person {
age: number;
}
Характер структурный системы типов TypeScript означает, что {last: "Johnson", age: 27}
является допустимым AgedPerson
, даже если вы не объявляете это как таковое (и даже если AgedPerson
не определено). И поскольку AgedPerson
является допустимым подтипом Person
, то {last: "Johnson", age: 27}
также является действительным Person
.
Теперь, когда люди используют литералы объекта, такие как {last: "Johnson", age: 27}
, они обычно не собираются добавлять такие дополнительные свойства, поэтому в TypeScript есть функция, называемая проверка избыточного свойства , которая обрабатывает литералы объекта так, как если бы они были точных типов и жалуются, если вы добавляете неизвестные свойства. Эта функция полезна, но ее очень легко обойти. Поэтому важно упомянуть, что если вы вообще реорганизуете свой код, предупреждение о том, что age
является избыточным свойством, может исчезнуть:
const ageDude = { last: 'Johnson', age: 27 };
const personDude: Person = ageDude; // no error
При этом для конкретного приведенного вами примера Я бы порекомендовал решение:
Object.assign<Person, Person>(dude, {
last: 'Johnson',
age: 27, // error
});
Здесь вы вручную указываете параметры типа generi c при вызове Object.assign
, где первый параметр типа соответствует типу первого аргумент функции, а параметр второго типа соответствует типу аргумента второй функции. Вы хотите, чтобы компилятор рассматривал оба из них как Person
, поэтому вы должны написать Object.assign<Person, Person>(...)
. И появляется ожидаемая ошибка избыточного свойства.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код