diff --git a/packages/compiler/src/output/value_util.ts b/packages/compiler/src/output/value_util.ts index c043800a6f..dd621c3817 100644 --- a/packages/compiler/src/output/value_util.ts +++ b/packages/compiler/src/output/value_util.ts @@ -21,7 +21,16 @@ export function convertValueToOutputAst( class _ValueOutputAstTransformer implements ValueTransformer { constructor(private ctx: OutputContext) {} visitArray(arr: any[], type: o.Type): o.Expression { - return o.literalArr(arr.map(value => visitValue(value, this, null)), type); + const values: o.Expression[] = []; + // Note Array.map() must not be used to convert the values because it will + // skip over empty elements in arrays constructed using `new Array(length)`, + // resulting in `undefined` elements. This breaks the type guarantee that + // all values in `o.LiteralArrayExpr` are of type `o.Expression`. + // See test case in `value_util_spec.ts`. + for (let i = 0; i < arr.length; ++i) { + values.push(visitValue(arr[i], this, null /* context */)); + } + return o.literalArr(values, type); } visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression { diff --git a/packages/compiler/test/output/value_util_spec.ts b/packages/compiler/test/output/value_util_spec.ts new file mode 100644 index 0000000000..536cf81527 --- /dev/null +++ b/packages/compiler/test/output/value_util_spec.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as o from '../../src/output/output_ast'; +import {convertValueToOutputAst} from '../../src/output/value_util'; + +describe('convertValueToOutputAst', () => { + it('should convert all array elements, including undefined', () => { + const ctx = null; + const value = new Array(3).concat('foo'); + const expr = convertValueToOutputAst(ctx !, value) as o.LiteralArrayExpr; + expect(expr instanceof o.LiteralArrayExpr); + expect(expr.entries.length).toBe(4); + for (let i = 0; i < 4; ++i) { + expect(expr.entries[i] instanceof o.Expression).toBe(true); + } + }); +});