Каковы преимущества аннотации Array‹T› в Closure Compiler по сравнению с простым массивом?

Я ожидал, что Closure Compiler выдаст предупреждение обо всех строках ниже, но только 3) отображается как проблема. Проверка содержимого массива с помощью Closure-Compiler затрагивает ту же самую точку, но мой вопрос: учитывая эти ограничения, какие преимущества дает аннотирование Array<T> по сравнению с Array? Я чувствую, что это ложное чувство безопасности.

// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
// @output_file_name default.js
// @warning_level VERBOSE
// ==/ClosureCompiler==

/** @type {!Array<!string>} */
var xs = [];
xs.push(42);       // 1) no warning
xs.push(null);     // 2) no warning
xs = 'foo'         // 3) warns - found: string, required: Array<string>
xs = [1,2,3];      // 4) no warning

Быстрое редактирование: вы можете поэкспериментировать с этим кодом на странице http://closure-compiler.appspot.com/


person overthink    schedule 28.10.2015    source источник
comment
Javascript не имеет ограничений по типу. Вы можете var xs = true; затем xs++; Если какой-либо другой интерпретатор не имеет ограничения, у вас не будет защиты.... однако большинство систем сообщит вам, если вы выполните неожиданные операции. Насколько я могу судить, это единственный плюс.   -  person Bonatti    schedule 28.10.2015


Ответы (2)


Я подозреваю, что это связано с тем, что определение externs для Array.prototype. push не совсем правильно. Если вы удалите тип @this, вы должны получить ожидаемые ошибки. Предположительно часть {length: number} была добавлена ​​по какой-то причине, поэтому ее удаление может где-то сломать существующий код.

person MatrixFrog    schedule 29.10.2015
comment
Это верно. Методы Array.prototype являются универсальными, они могут принимать любой массивоподобный объект (NodeList, TypedArray, Arguments и т. д.). Однако это будет исправлено, когда Array реализует IArrayLike (который мы представили в последнем выпуске). Тогда вместо {length:number}|Array<T> будет просто IArrayLike<T>, что и будет работать так, как мы хотим. - person John; 30.10.2015
comment
@Джон Спасибо за это. Как насчет дела xs = [1,2,3]; выше? xs явно является Array<string>, а [1,2,3] в худшем случае выводится как Array<*>. Вроде должно предупреждать? - person overthink; 02.11.2015
comment
Это немного отличается, это просто то, что литерал объекта выводится как Array‹?› и это меняется в выводе нового типа компилятора. - person John; 05.11.2015

Вы получите те же преимущества универсальных шаблонов, что и другие статические языки.
Допустим, вы хотите создать массив строк, а затем отсортировать их по длине.

var arr = [];    
arr.sort(function(a, b) { return a.length - b.length; });

Если вы аннотируете массив как Array, вы сможете добавить число в массив, и компилятор закрытия не будет жаловаться.
В конце концов вы столкнетесь с исключением, потому что число не имеет свойства длины.
Если вы аннотируете массив как массив строк Array<string>, то вы убедитесь, что свойство длины будет существовать и что никто не сможет вставить какой-либо другой тип, кроме строки.

Я не понимаю, почему вы не получаете ошибок компиляции со строкой, но если вы попробуете это с числом, вы получите другие результаты компиляции.

// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
// @output_file_name default.js
// @warning_level VERBOSE
// ==/ClosureCompiler==

/** @type {!Array<!number>} */
var xs = [];
xs.push(42);
console.log(xs[0].length);

=> 
Number of warnings: 1

JSC_INEXISTENT_PROPERTY: Property length never defined on Number at line 4 character 18
console.log(xs[0].length);
              ^ 
person Sagi    schedule 28.10.2015
comment
В моем примере выше я аннотирую xs как Array<string> и могу добавлять нестроки в массив. xs сохраняет тип Array<string>, но теперь содержит нестроки. Я хочу, чтобы все работало так, как вы описываете :) - person overthink; 28.10.2015
comment
Вы используете компиляцию в расширенном режиме? - person Sagi; 28.10.2015
comment
Я не в этом примере, нет. Но, похоже, это не влияет на проверку типов, а только на то, насколько агрессивно минимизируется/преобразуется код. developers.google.com/closure/compiler/docs/compilation_levels - person overthink; 28.10.2015
comment
У меня сложилось впечатление, что компилятор выдал предупреждения, но не обеспечил такой уровень безопасности типов (т.е. гарантировал, что не будут добавлены несоответствующие типы)? - person Jared Smith; 28.10.2015