Skip to content

Commit

Permalink
fix(compiler-cli): unwrap expressions with type parameters in query r…
Browse files Browse the repository at this point in the history
…ead property (#54647)

Fixes that a query like `viewChild('locator', {read: ElementRef<HTMLElement>})` would throw because we didn't account for expressions with type parameters.

I've also included support for parenthesized expressions and `as` expressions since it's pretty easy to support them.

Fixes #54645.

PR Close #54647
  • Loading branch information
crisbeto authored and pkozlowski-opensource committed Feb 28, 2024
1 parent 7ca08aa commit 917b9bd
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ function parseLocator(expression: ts.Expression, reflector: ReflectionHost): str
* live outside of the class in the static class definition.
*/
function parseReadOption(value: ts.Expression): o.Expression {
if (ts.isExpressionWithTypeArguments(value) || ts.isParenthesizedExpression(value) ||
ts.isAsExpression(value)) {
return parseReadOption(value.expression);
}

if (ts.isPropertyAccessExpression(value) && ts.isIdentifier(value.expression) ||
ts.isIdentifier(value)) {
return new o.WrappedNodeExpr(value);
Expand Down
4 changes: 3 additions & 1 deletion packages/compiler-cli/src/ngtsc/testing/fake_core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export const ViewChildren = callablePropDecorator();
export type ModuleWithProviders<T = any> = any;

export class ChangeDetectorRef {}
export class ElementRef {}
export class ElementRef<T = any> {
nativeElement!: T;
}
export class Injector {}
export class TemplateRef<T = any> {}
export class ViewContainerRef {}
Expand Down
48 changes: 48 additions & 0 deletions packages/compiler-cli/test/ngtsc/authoring_queries_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,54 @@ runInEachFileSystem(() => {
expect(js).toContain(`i0.ɵɵqueryAdvance(2);`);
});

it('should support viewChild with `read` pointing to an expression with a generic', () => {
env.write('test.ts', `
import {Component, viewChild, ElementRef} from '@angular/core';
@Component({selector: 'test', template: ''})
export class TestDir {
el = viewChild('myLocator', {read: ElementRef<HTMLElement>});
}
`);
env.driveMain();

const js = env.getContents('test.js');
expect(js).toContain(`i0.ɵɵviewQuerySignal(ctx.el, _c0, 5, ElementRef);`);
expect(js).toContain(`i0.ɵɵqueryAdvance();`);
});

it('should support viewChild with `read` pointing to a parenthesized expression', () => {
env.write('test.ts', `
import {Component, viewChild, ElementRef} from '@angular/core';
@Component({selector: 'test', template: ''})
export class TestDir {
el = viewChild('myLocator', {read: ((((ElementRef))))});
}
`);
env.driveMain();

const js = env.getContents('test.js');
expect(js).toContain(`i0.ɵɵviewQuerySignal(ctx.el, _c0, 5, ElementRef);`);
expect(js).toContain(`i0.ɵɵqueryAdvance();`);
});

it('should support viewChild with `read` pointing to an `as` expression', () => {
env.write('test.ts', `
import {Component, viewChild, ElementRef} from '@angular/core';
@Component({selector: 'test', template: ''})
export class TestDir {
el = viewChild('myLocator', {read: ElementRef as any});
}
`);
env.driveMain();

const js = env.getContents('test.js');
expect(js).toContain(`i0.ɵɵviewQuerySignal(ctx.el, _c0, 5, ElementRef);`);
expect(js).toContain(`i0.ɵɵqueryAdvance();`);
});

it('should handle a basic viewChildren', () => {
env.write('test.ts', `
import {Component, viewChildren} from '@angular/core';
Expand Down

0 comments on commit 917b9bd

Please sign in to comment.