#typescript
#typescript
Вопрос:
Когда я смотрю на подпись Object.assign
, я вижу, что она использует типы пересечений, но поведение не то, что я ожидал.
Я хочу использовать Object.assign
для объединения некоторых изменений со старым объектом для создания нового объекта (как это принято в JS при следовании неизменяемым шаблонам данных) и заставить TypeScript проверить правильность частей и результата, но, похоже, TypeScript допускает все без ошибок.
Например:
interface Thing {
name: string;
age: number;
fav: boolean;
}
let oldThing: Thing = {
name: "Aaa",
age: 123,
fav: false
};
let newThing: Thing = Object.assign({}, oldThing, {
name: "Bbb",
age: "abc", // should be type error
fake: "fakey" // should be unknown prop error
});
Почему Object.assign
разрешить это неправильное присвоение Thing
? Есть ли способ сделать эту работу близкой к тому, что я ожидал?
Комментарии:
1. Вы выполнили все требования, чтобы компилятор typescript был доволен, но помните, что в конце концов ваш код выполняется на javascript, а javascript просто не волнует.
2. Да, мне постоянно об этом напоминают. 🙂 Но мой вопрос здесь в том, почему он компилируется ? Кажется, что назначение
Thing
должно быть ошибкой компиляции для этих свойств. Возможно, я не понимаю, как средство проверки типов проверяет назначение.3. Прошло почти 3 года, до сих пор нет прогресса
Object.assign
. Я немного смущен тем, почему так мало информации об этой проблеме. Я думаю, это должно быть описано в официальных документах.
Ответ №1:
Причина, по которой вы интуитивно ожидаете здесь ошибки, заключается в том, что тип пересечения, созданный для возвращаемого значения Object.assign
, является абсурдным и не может быть занят никакими реальными значениями. Однако TypeScript не имеет способа проверить это. Возвращаемое отсюда значение Object.assign
вводится следующим образом:
{
name: string,
age: string amp; number,
fav: boolean,
fake: string
}
Конечно, нет фактического значения, которое было бы и тем, и другим string amp; number
, но компилятор этого не знает. Он успешно создает этот абсурдный тип, затем, когда вы пытаетесь присвоить его Thing
, проверяет, что тип каждого свойства в Thing
удовлетворяется соответствующим свойством в возвращаемом значении. Поскольку это так (каждый из name
age
и fav
присутствуют и удовлетворяют, по крайней мере, требуемому интерфейсу в Thing
), назначение выполняется успешно.
Если бы вы разрешили выводить тип newThing
, а затем попытались присвоить что-либо age
свойству, вы бы увидели проблему:
let newThing = Object.assign({}, oldThing, {
name: "Bbb",
age: "abc",
fake: "fakey"
});
newThing.age = 10; // Compiler error because 10 is not a string
newThing.age = "10"; // Compiler error because "10" is not a number
Комментарии:
1. Спасибо, это забавно. Так что, я думаю
Object.assign
, на самом деле это не помогает обеспечить безопасность типов для подобных вещей. С нетерпением ждем, чтобы вместо этого TS поддерживал распространение объектов…
Ответ №2:
Вы можете заставить TypeScript проверять, используя утверждения типа: т.е. as Thing
Или <Thing>
interface Thing {
name: string;
age: number;
fav?: boolean; // You may need to mark this as optional depending on
// your requirement, otherwise TypeScript will
// generate missing prop error
}
//...
let newThing: Thing = Object.assign({}, oldThing, {
name: "Bbb",
age: "abc", // will cause type error
fake: "fakey" // howerver, no error for unknown prop
} as Thing);
Комментарии:
1. Это правильный ответ. Спасибо! Я не знал, что могу указать тип объекта с
<Thing>{ ... }
помощью синтаксиса.