2

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

// ==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/

+0

Javascript не имеет ограничений по типу. Вы можете «var xs = true;» then «xs ++;» Если какой-либо другой интерпретатор имеет ограничение, у вас не будет безопасности ... однако, большинство систем сообщит вам, если вы делаете неожиданные операции. Насколько я могу судить, это единственное преимущество. – Bonatti

ответ

0

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

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

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

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

// ==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); 
      ^
+0

В моем примере выше я комментирую 'xs' как' Array ' и могу добавить в массив нестроковые. 'xs' сохраняет тип' Array ', но теперь содержит нестрочные. Я хочу, чтобы он работал так, как вы описываете :) – overthink

+0

Вы используете компиляцию в расширенном режиме? – Sagi

+0

Я не в этом примере, нет. Но, похоже, это не влияет на проверку типов, а только на то, насколько агрессивно код минимизируется/трансформируется. https://developers.google.com/closure/compiler/docs/compilation_levels – overthink

1

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

+1

Это правда. Методы Array.prototype являются общими, они могут принимать любой объект типа «массив» (NodeList, TypedArray, Arguments и т. Д.). Однако это будет исправлено, если Array реализует IArrayLike (который мы ввели в последнем выпуске). Тогда вместо '{length: number} | Array ' будет просто 'IArrayLike ', который будет работать так, как мы хотим. – John

+0

@John Спасибо. Что относительно 'xs = [1,2,3];' case выше? 'xs' явно' Array 'и' [1,2,3] 'кажется худшим для вывода как' Array <*> '. Похоже, это должно предупредить? – overthink

+0

Это немного отличается, это просто, что литерал объекта выводится как «Array » и это изменяет в компиляторах «вывод нового типа». – John

Смежные вопросы