Skip to content

Commit d47fef7

Browse files
tomalaforgeatscott
authored andcommitted
fix(common): strict type checking for ngtemplateoutlet (#48374)
When we create a context to inject inside our ngTemplateOutlet, the context was declare as Object, therefore, there are no compilation error. Now if we add a context, we get error at compile type. BREAKING CHANGE: If the 'ngTemplateOutletContext' is different from the context, it will result in a compile-time error. Before the change, the following template was compiling: ```typescript interface MyContext { $implicit: string; } @component({ standalone: true, imports: [NgTemplateOutlet], selector: 'person', template: ` <ng-container *ngTemplateOutlet=" myTemplateRef; context: { $implicit: 'test', xxx: 'xxx' } "></ng-container> `, }) export class PersonComponent { myTemplateRef!: TemplateRef<MyContext>; } ``` However, it does not compile now because the 'xxx' property does not exist in 'MyContext', resulting in the error: 'Type '{ $implicit: string; xxx: string; }' is not assignable to type 'MyContext'.' The solution is either: - add the 'xxx' property to 'MyContext' with the correct type or - add '$any(...)' inside the template to make the error disappear. However, adding '$any(...)' does not correct the error but only preserves the previous behavior of the code. fix #43510 PR Close #48374
1 parent 585e34b commit d47fef7

File tree

3 files changed

+18
-18
lines changed

3 files changed

+18
-18
lines changed

goldens/public-api/common/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -703,17 +703,17 @@ export class NgSwitchDefault {
703703
}
704704

705705
// @public
706-
export class NgTemplateOutlet implements OnChanges {
706+
export class NgTemplateOutlet<C = unknown> implements OnChanges {
707707
constructor(_viewContainerRef: ViewContainerRef);
708708
// (undocumented)
709709
ngOnChanges(changes: SimpleChanges): void;
710-
ngTemplateOutlet: TemplateRef<any> | null;
711-
ngTemplateOutletContext: Object | null;
710+
ngTemplateOutlet: TemplateRef<C> | null;
711+
ngTemplateOutletContext: C | null;
712712
ngTemplateOutletInjector: Injector | null;
713713
// (undocumented)
714-
static ɵdir: i0.ɵɵDirectiveDeclaration<NgTemplateOutlet, "[ngTemplateOutlet]", never, { "ngTemplateOutletContext": { "alias": "ngTemplateOutletContext"; "required": false; }; "ngTemplateOutlet": { "alias": "ngTemplateOutlet"; "required": false; }; "ngTemplateOutletInjector": { "alias": "ngTemplateOutletInjector"; "required": false; }; }, {}, never, never, true, never>;
714+
static ɵdir: i0.ɵɵDirectiveDeclaration<NgTemplateOutlet<any>, "[ngTemplateOutlet]", never, { "ngTemplateOutletContext": { "alias": "ngTemplateOutletContext"; "required": false; }; "ngTemplateOutlet": { "alias": "ngTemplateOutlet"; "required": false; }; "ngTemplateOutletInjector": { "alias": "ngTemplateOutletInjector"; "required": false; }; }, {}, never, never, true, never>;
715715
// (undocumented)
716-
static ɵfac: i0.ɵɵFactoryDeclaration<NgTemplateOutlet, never>;
716+
static ɵfac: i0.ɵɵFactoryDeclaration<NgTemplateOutlet<any>, never>;
717717
}
718718

719719
// @public

packages/common/src/directives/ng_template_outlet.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,21 @@ import {Directive, EmbeddedViewRef, Injector, Input, OnChanges, SimpleChanges, T
3636
selector: '[ngTemplateOutlet]',
3737
standalone: true,
3838
})
39-
export class NgTemplateOutlet implements OnChanges {
40-
private _viewRef: EmbeddedViewRef<any>|null = null;
39+
export class NgTemplateOutlet<C = unknown> implements OnChanges {
40+
private _viewRef: EmbeddedViewRef<C>|null = null;
4141

4242
/**
4343
* A context object to attach to the {@link EmbeddedViewRef}. This should be an
4444
* object, the object's keys will be available for binding by the local template `let`
4545
* declarations.
4646
* Using the key `$implicit` in the context object will set its value as default.
4747
*/
48-
@Input() public ngTemplateOutletContext: Object|null = null;
48+
@Input() public ngTemplateOutletContext: C|null = null;
4949

5050
/**
5151
* A string defining the template reference and optionally the context object for the template.
5252
*/
53-
@Input() public ngTemplateOutlet: TemplateRef<any>|null = null;
53+
@Input() public ngTemplateOutlet: TemplateRef<C>|null = null;
5454

5555
/** Injector to be used within the embedded view. */
5656
@Input() public ngTemplateOutletInjector: Injector|null = null;
@@ -70,10 +70,11 @@ export class NgTemplateOutlet implements OnChanges {
7070
const {
7171
ngTemplateOutlet: template,
7272
ngTemplateOutletContext: context,
73-
ngTemplateOutletInjector: injector
73+
ngTemplateOutletInjector: injector,
7474
} = this;
75-
this._viewRef = viewContainerRef.createEmbeddedView(
76-
template, context, injector ? {injector} : undefined);
75+
this._viewRef =
76+
viewContainerRef.createEmbeddedView(
77+
template, context, injector ? {injector} : undefined) as EmbeddedViewRef<C>;
7778
} else {
7879
this._viewRef = null;
7980
}

packages/compiler-cli/src/ngtsc/testing/fake_common/index.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,16 @@ export declare class NgIf<T = unknown> {
5757
ctx is NgIfContext<Exclude<T, false|0|''|null|undefined>>;
5858
}
5959

60-
export declare class NgTemplateOutlet {
61-
ngTemplateOutlet: TemplateRef<any>|null;
62-
ngTemplateOutletContext: Object|null;
60+
export declare class NgTemplateOutlet<C = unknown> {
61+
ngTemplateOutlet: TemplateRef<C>|null;
62+
ngTemplateOutletContext: C|null;
6363

64-
static ɵdir: ɵɵDirectiveDeclaration < NgTemplateOutlet, '[ngTemplateOutlet]', never, {
64+
static ɵdir: ɵɵDirectiveDeclaration < NgTemplateOutlet<any>, '[ngTemplateOutlet]', never, {
6565
'ngTemplateOutlet': 'ngTemplateOutlet';
6666
'ngTemplateOutletContext': 'ngTemplateOutletContext';
6767
}
6868
, {}, never > ;
69-
static ngTemplateContextGuard<T>(dir: NgIf<T>, ctx: any):
70-
ctx is NgIfContext<Exclude<T, false|0|''|null|undefined>>;
69+
static ngTemplateContextGuard<T>(dir: NgTemplateOutlet<T>, ctx: any): ctx is T;
7170
}
7271

7372
export declare class DatePipe {

0 commit comments

Comments
 (0)