TypeScript позволяет вам переопределить прогнозируемое и проанализированное значение типов любым удобным для вас способом. Это делается с помощью механизма, называемого "утверждением типа". Простыми словами утверждение типа в TypeScript - это когда вы говорите компилятору, что вы знаете о типах лучше, чем он, и что он не должен сам догадываться.
Обычный вариант использования утверждения типа - это когда вы портируете код с JavaScript на TypeScript. Например, рассмотрим следующий шаблон:
var foo = {};
foo.bar = 123; // Ошибка: свойство 'bar' не существует в `{}`
foo.bas = 'hello'; // Ошибка: свойство 'bas' не существует в `{}`
Здесь ошибки в коде, потому что ожидаемый тип для foo
это {}
, т.е. объект без свойств. Поэтому вы не можете добавлять bar
или bas
к нему. Вы можете исправить это просто с помощью утверждения типа as Foo
:
interface Foo {
bar: number;
bas: string;
}
var foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';
Первоначально был добавлен синтаксис <foo>
. Это продемонстрировано ниже:
var foo: any;
var bar = <string> foo; // bar теперь имеет тип "string"
Однако существует двусмысленность в грамматике языка при использовании утверждений в стиле <foo>
в JSX:
var foo = <string>bar;
</string>
Поэтому сейчас рекомендуется просто использовать as foo
для единообразия.
Причина, по которой это не называется "приведением типа", заключается в том, что приведение обычно подразумевает некоторую поддержку среды выполнения. Тем не менее, утверждения типа - это просто конструкция для компиляции и способ для вас дать подсказки компилятору о том, как вы хотите, чтобы ваш код был проанализирован.
Во многих случаях утверждение позволит вам легко перенести старый код (и даже скопипастить иные примеры кода в вашу кодовую базу). Тем не менее, вы должны быть осторожны с использованием утверждений. Возьмите наш исходный код в качестве примера, компилятор не защитит вас от того, что вы забудете добавить свойства, которые вы обещали:
interface Foo {
bar: number;
bas: string;
}
var foo = {} as Foo;
// аааа .... забыть что-нибудь?
Также другой распространенной идеей является использовать утверждения в качестве средства обеспечения автозаполнения, например:
interface Foo {
bar: number;
bas: string;
}
var foo = <Foo>{
// компилятор предоставит автозаполнение для свойств Foo
// Но разработчику легко забыть добавить все свойства
// Также этот код может сломаться, если Foo подвергнется рефакторингу (например, добавлено новое свойство)
};
но опасность здесь та же, если вы забудете свойство, компилятор не будет жаловаться. Лучше, если вы сделаете следующее:
interface Foo {
bar: number;
bas: string;
}
var foo:Foo = {
// компилятор предоставит автозаполнение для свойств Foo
};
В некоторых случаях вам может потребоваться создать временную переменную, но, по крайней мере, вы не будете давать (возможно, ложные) обещания и вместо этого будете полагаться на предполагаемый комилятором тип.
Утверждение типа, несмотря на то, что, как мы показали, немного небезопасно, не является «чем-то абсолютно запрещённым». Например. следующее является очень даже допустимым случаем использования (например, пользователь думает, что переданное событие будет более конкретным случаем события), и утверждение типа работает как ожидалось:
function handler (event: Event) {
let mouseEvent = event as MouseEvent;
}
Однако следующее, скорее всего, ошибка, и TypeScript будет жаловаться, как показано, несмотря на утверждение типа пользователем:
function handler(event: Event) {
let element = event as HTMLElement; // Ошибка: Ни тип 'Event' ни тип 'HTMLElement' не могут быть присвоены
}
Если вы все еще хотите этот тип, вы можете использовать двойное утверждение, а именно сначала сделайте утверждение any
, которое совместимо со всеми типами, и поэтому компилятор больше не жалуется:
function handler(event: Event) {
let element = event as any as HTMLElement; // Okay!
}
По сути, утверждение от типа S
к T
успешно выполняется, если либо S
является подтипом T
, либо T
является подтипом S
. Это делается для обеспечения дополнительной безопасности при выполнении утверждений типа ... совершенно безумные утверждения могут быть очень небезопасными, и вам нужно использовать any
, чтобы можно было их использовать.