Страницы

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

пятница, 10 января 2020 г.

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

#typescript


Всем привет. Изучаю тайпскрипт, и в первую очередь меня интересуют интерфейсы. Для
проверки того, что как они работают, я написал следующее:

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, или это просто
рекламный ход.
    


Ответы

Ответ 1



Типизация, очевидно, есть. Просто в данном случае происходят некорректные проверки. Если разобрать первый пример: Есть интерфейс, в котором указаны конкретные поля, и указанным полям проставлен конкретный тип. Что происходит дальше, объявляется класс, у которого присутствуют эти поля, но им задан тип 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' Пример для проверки

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

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