feat(ivy): type-checking for some previously unsupported expressions (#29698)

This commit adds support for the generation of type-checking expressions for
forms which were previously unsupported:

* array literals
* map literals
* keyed property accesses
* non-null assertions

Testing strategy: TCB tests included.

Fixes #29327
FW-1218 #resolve

PR Close #29698
This commit is contained in:
Alex Rickabaugh 2019-03-22 17:18:47 -07:00 committed by Ben Lesh
parent e3d5d41140
commit 9f5288dad3
2 changed files with 37 additions and 1 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AST, ASTWithSource, Binary, Conditional, Interpolation, LiteralPrimitive, MethodCall, PropertyRead} from '@angular/compiler';
import {AST, ASTWithSource, Binary, Conditional, Interpolation, KeyedRead, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PropertyRead} from '@angular/compiler';
import * as ts from 'typescript';
const BINARY_OPS = new Map<string, ts.SyntaxKind>([
@ -76,6 +76,22 @@ export function astToTypescript(
const trueExpr = astToTypescript(ast.trueExp, maybeResolve);
const falseExpr = astToTypescript(ast.falseExp, maybeResolve);
return ts.createParen(ts.createConditional(condExpr, trueExpr, falseExpr));
} else if (ast instanceof LiteralArray) {
const elements = ast.expressions.map(expr => astToTypescript(expr, maybeResolve));
return ts.createArrayLiteral(elements);
} else if (ast instanceof LiteralMap) {
const properties = ast.keys.map(({key}, idx) => {
const value = astToTypescript(ast.values[idx], maybeResolve);
return ts.createPropertyAssignment(ts.createStringLiteral(key), value);
});
return ts.createObjectLiteral(properties, true);
} else if (ast instanceof KeyedRead) {
const receiver = astToTypescript(ast.obj, maybeResolve);
const key = astToTypescript(ast.key, maybeResolve);
return ts.createElementAccess(receiver, key);
} else if (ast instanceof NonNullAssert) {
const expr = astToTypescript(ast.expression, maybeResolve);
return ts.createNonNullExpression(expr);
} else {
throw new Error(`Unknown node type: ${Object.getPrototypeOf(ast).constructor}`);
}

View File

@ -19,6 +19,26 @@ import {generateTypeCheckBlock} from '../src/type_check_block';
describe('type check blocks', () => {
it('should generate a basic block for a binding',
() => { expect(tcb('{{hello}}')).toContain('ctx.hello;'); });
it('should generate literal map expressions', () => {
const TEMPLATE = '{{ method({foo: a, bar: b}) }}';
expect(tcb(TEMPLATE)).toContain('ctx.method({ "foo": ctx.a, "bar": ctx.b });');
});
it('should generate literal array expressions', () => {
const TEMPLATE = '{{ method([a, b]) }}';
expect(tcb(TEMPLATE)).toContain('ctx.method([ctx.a, ctx.b]);');
});
it('should handle non-null assertions', () => {
const TEMPLATE = `{{a!}}`;
expect(tcb(TEMPLATE)).toContain('ctx.a!;');
});
it('should handle keyed property access', () => {
const TEMPLATE = `{{a[b]}}`;
expect(tcb(TEMPLATE)).toContain('ctx.a[ctx.b];');
});
});
function getClass(sf: ts.SourceFile, name: string): ClassDeclaration<ts.ClassDeclaration> {