Объявление и проверка типов в примерах
Google Closure Compiler, как и любой кошерный компилятор, старается проверить правильность кода и предупредить о возможных ошибках.
Первым делом он, разумеется, проверяет структуру кода и сразу же выдает такие ошибки как пропущенная скобка или лишняя запятая.
Но, кроме этого, он умеет проверять типы переменных, используя как свои собственные знания о встроенных javascript-функциях и преобразованиях типов,
так и информацию о типах из JSDoc, указываемую javascript-разработчиком.
Это обеспечивает то, чем так гордятся компилируемые языки - статическую проверку типов, что позволяет избежать лишних ошибок во время выполнения.
Для включения проверки типов используется флаг --check_types . Кроме того, --warning_level не должен быть QUIET , иначе вы не увидите предупреждений.
Самый очевидный способ задать тип - это использовать аннотацию. Полный список аннотаций вы найдете в документации.
В следующем примере параметр id функции f1 присваивается переменной boolVar другого типа:
/** @param {number} id */
function f1(id) {
/** @type {boolean} */
var boolVar
boolVar = id // (!)
}
Компиляция с флагом --check_types выдаст ошибку:
d.js:6: WARNING - assignment
found : number
required: boolean
boolVar = id
^
Действительно: произошло присвоение значения типа number переменной типа boolean .
Еще пример, на этот раз вызов функции с некорректным параметром:
/** @param {number} id */
function f1(id) {
f2(id) // (!)
}
/** @param {string} id */
function f2(id) { }
Такой функции приведет к ошибке:
f.js:3: WARNING - actual parameter 1 of f2 does not match formal parameter
found : number
required: string
f2(id)
^
Действительно, вызов функции f2 произошел с числовым типом вместо строки.
Кстати, по этому примеру видно, что тип переменной сохраняется после возврата из функции и других аналогичных операций.
Это возможно, благодаря графу взаимодействий и выведению (infer) типов, которое осуществляет компилятор.
Google Closure Compiler знает, как операторы javascript преобразуют типы. Такой код уже не выдаст ошибку:
/** @param {number} id */
function f1(id) {
/** @type {boolean} */
var boolVar
boolVar = !!id
}
Действительно - переменная преобразована к типу boolean двойным оператором НЕ.
А код boolVar = 'test-'+id выдаст ошибку, т.к. конкатенация со строкой дает тип string .
Google Closure Compiler содержит описания большинства встроенных объектов и функций javascript вместе с типами параметров и результатов.
Например, объектный тип Node соответствует узлу DOM.
Пример проверки:
/** @param {Node} node */
function removeNode(node) {
node.parentNode.removeChild(node)
}
document.onclick = function() {
removeNode("123")
}
Выдаст
script.js:6: WARNING - actual parameter 1 of removeNode does not match formal parameter
found : string
required: (Node|null)
removeNode("123")
Обратите внимание - в этом примере компилятор выдает required: Node|null . Это потому, что указание объектного типа (не элементарного) подразумевает, что в функцию может быть передан null .
В следующем примере тип указан жестко, без возможности обнуления.
Пример: Объект не-null
/** @param {!Node} node */
function removeNode(node) {
node.parentNode.removeChild(node)
}
document.onclick = function() {
removeNode("123")
}
Выдаст
script.js:3: WARNING - actual parameter 1 of Node.prototype.removeChild does not match formal parameter
found : (Node|string)
required: (Node|null)
node.parentNode.removeChild(node)
^
Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: externs.zip находится в корне архива compiler.jar , или в соответствующей директории SVN: http://closure-compiler.googlecode.com/svn/trunk/externs/.
В Google Closure Library есть функции проверки типов: goog.isArray , goog.isDef , goog.isNumber и т.п.
Google Closure Compiler знает о них и понимает, что внутри следующего if переменная может быть только функцией:
if (goog.isFunction(f)) {
f.apply(1,2,3)
}
Выдаст следующую ошибку:
d.js:2: WARNING - Function Function.apply: called with 3 argument(s). Function requires at least 0 argument(s) and no mo
re than 2 argument(s).
f.apply(1,2,3)
^
То есть, компилятор увидел, что f - это функция, то есть объект типа Function . Метод apply для экземпляра такого объекта принимает только 2 аргумента - обнаружена ошибка. Хорошо, что сейчас, а не позже, в момент запуска.
Из нескольких примеров, которые мы рассмотрели, должна быть понятна общая логика проверки типов.
Соответствующие различным типам и ограничениям на типы аннотации вы можете найти в Документации Google. В частности, возможно указание нескольких возможных типов, типа undefined и т.п.
Также можно указывать количество и тип параметров функции, ключевого слова this , объявлять классы, приватные методы и интерфейсы.
Проверка типов javascript, предоставляемая Google Closure Compiler - пожалуй, самая продвинутая из существующих на сегодняшний день.
C ней аннотации, документирующие типы и параметры, становятся не просто украшением, а реальным средством проверки, уменьшающим количество ошибок на production.
|
как именно скоппиплировать с режимом --check_types
у меня есть bat файлик в нем:
closure\closure\bin\calcdeps.py -i main.js -o compiled -c compiler.jar -f "--compilation_level=ADVANCED_OPTIMIZATIONS" > main-compiled.js
подскажите, пожайлуста!
Интересная система, вот бы её прикрутить к Eclipse как билдер, чтобы оно код проверяло автоматически.
Довольно забавная игра и очень сложная в некоторых местах, но нет ничего, из чего вы не смогли бы хотя бы споткнуться, проявив немного терпения в игре bloxorz.