2016-10-06 4 views
1

Когда я смотрю на signature of Object.assign, я вижу, что он использует типы пересечений, но поведение не то, что я ожидал.TypeScript Object.assign confusion

Я хочу использовать 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 
}); 

Here it is in the playground.

Почему Object.assign позволяют это неправильное присвоение Thing? Есть ли способ приблизить эту работу к тому, что я ожидал?

+0

Вы выполнили все требования, чтобы сделать машинопись компилятор счастливым, но помните, в конце концов, это javascr ipt, который запускает ваш код, а javascript просто не волнует. –

+0

Да, я все время вспоминаю об этом. :) Но вот мой вопрос, почему он * компилирует *? Кажется, что присвоение 'Thing' должно быть ошибкой компиляции этих свойств. Может быть, я не понимаю, как проверяющий тип проверяет назначение. – Aaron

ответ

4

Причина, по которой вы интуитивно ожидаете ошибку здесь, заключается в том, что тип пересечения, построенный для возвращаемого значения Object.assign, абсурден и не может быть занят никакими реальными значениями. Однако TypeScript не имеет возможности проверить это. Возвращаемое значение Object.assign здесь набирается в следующем виде:

{ 
    name: string, 
    age: string & number, 
    fav: boolean, 
    fake: string 
} 

Конечно нет фактического значения, которая является одновременно string & number, но компилятор не знает, что. Он счастливо конструирует этот абсурдный тип, затем, когда вы пытаетесь присвоить его Thing, проверяется, что тип каждого свойства в Thing удовлетворяется соответствующим свойством в возвращаемом значении. Так как это так (каждый из name, и 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, поддерживающего распространение объекта ... – Aaron

0

Вы можете заставить машинопись, чтобы проверить, добавив <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, <Thing>{ 
    name: "Bbb", 
    age: "abc",  // will generate type error 
    fake: "fakey" // howerver, this will not generate unknown prop error 
}); 
Смежные вопросы