Страницы

Поиск по вопросам

среда, 20 февраля 2019 г.

в чем заключается типизация в тайпскрипте?

Всем привет. Изучаю тайпскрипт, и в первую очередь меня интересуют интерфейсы. Для проверки того, что как они работают, я написал следующее:
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'
Пример для проверки

Комментариев нет:

Отправить комментарий