Всем привет. Изучаю тайпскрипт, и в первую очередь меня интересуют интерфейсы. Для проверки того, что как они работают, я написал следующее:
interface I1 {
stringProp: string;
numProp: number;
}
printI1(i1: I1): void {
console.log(i1);
console.log(i1.numProp * 2);
}
От поведения этого интерфейсного типа я ожидаю следующего:
В stringProp может попасть только строка, а в в numprop - только число. Интерфейс позволит мне абстрагироваться от полей того типа, который я привожу к нему.
Ну хорошо, возьмем такой класс.
class T1 {
public propNotExistedInInterface: boolean = true;
public stringProp: any;
public numProp: any;
}
И попробуем привести его к I1 следующим образом.
let a: T1 = new T1();
a.stringProp = 13;
a.numProp = "asd";
this.printI1(a);
И результат:
Object { propNotExistedInInterface: true, stringProp: 13, numProp: "asd" }
NaN
Ни одного из моих ожиданий не оправдалось. Ни одного предупреждения транслятора. Так в чем заключается хвалёная типизация? пробовал менять NoImplicitAny - один и тот же результат.
Следующий пример:
Берем интерфейс:
interface INumberWithFuncProcessor {
num: number;
func(number): string;
}
Мы будем использовать его в качестве параметра метода (при этом допускаем ошибку):
useProcessor(param: INumberWithFuncProcessor): string {
return param.func(param); // ошибка, подразумевали param.num
}
И используем наш метод:
let something = this.useProcessor(
{
num: 12,
func: (x) => { return x.toString() }
});
При попытке вывести something на экран мы увидим [object Object]. Транслятор молчит. По всей видимости в наш параметр интерфейсного типа попадает что-то вроде.
{ num: number; func(object): string; }
Вопрос, как видите, риторический: есть ли статическая типизация в ts, или это просто рекламный ход.
Ответ
Типизация, очевидно, есть. Просто в данном случае происходят некорректные проверки.
Если разобрать первый пример:
Есть интерфейс, в котором указаны конкретные поля, и указанным полям проставлен конкретный тип.
Что происходит дальше, объявляется класс, у которого присутствуют эти поля, но им задан тип any. Что такое any - это заглушка, которая показывает, что тип может быть любой. В следствие этого переменную типа any можно присвоить переменной любого типа.
Что получилось в итоге, компилятор не проверяет реальный тип полей, так как типизация работает только во время компиляции, и чтобы определить какое именно из значений в итоге будет у поля, и, соответственно, какой тип, компилятору нужно выполнить всю программу. В общем случае это неразрешимая задача, и определение типа any отдается на откуп программисту.
В то же время, если убрать одно из полей в классе T1, например stringProp, компилятор может проверить, что у объекта передаваемого класса, отсутствуют обязательное поле и кинет ошибку. А также, если вместо any использовать конкретные типы, например public stringProp: number; компилятор опять подскажет, что типы не совпадают.
Примеры для проверки
Что касается второго примера:
interface INumberWithFuncProcessor {
num: number;
func(number): string;
}
Ошибочно само описание интерфейса, и при выборе опции noImplicitAny компилятор подсказывает, что number - это параметр, и так как у него не указан напрямую тип, его тип будет any и как мы помним - any не проверяется в compile-time. Таким образом, вполне нормально передавать в него переменные любого типа.
Если же указать конкретный тип параметра, например:
interface INumberWithFuncProcessor {
num: number;
func(a:number): string;
}
То компилятор вполне резонно покажет ошибку:
Argument of type 'INumberWithFuncProcessor' is not assignable to parameter of type 'number'
Пример для проверки
Комментариев нет:
Отправить комментарий