NgTemplateOutlet Typed Checking (Part 2)(Inline)
Tags: angular, typescript
Published: 2022-12-12 08:44:08

In my previous article, we saw how to strictly type-check the `NgTemplateOutlet` when it is used on a child component. In this article, we will see how to do this when the `TemplateRef` is located inside the same template as the `NgTemplateOutletDirective`

We define the following template where our `TemplateOutlet` directive is embedded inside the `#personRef` template. 

```html
<ng-container
  *ngTemplateOutlet="
    personRef;
    context: { $implicit: person.name, age: person.age }
  ">
</ng-container>

<ng-template #personRef let-name let-age="age">
  {{ name }}: {{ age }}
</ng-template>
```
This template is working perfectly but we don't have any autocompletion or type inference. 

![No type inference](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6rhsyr1y69708xud9bt.png)


I invite you to read my previous article on [NgTemplateOutlet Type Checking](https://dev.to/this-is-angular/ngtemplateoutlet-typed-checked-with-contentchild-2phe) and [Directive Type Checking](https://dev.to/this-is-angular/directive-type-checking-45oe) to have a better understanding over the following step. 

As described in my previous article, we can create a directive with a `ngTemplateContextGuard` that defines our context `PersonContext`.

```typescript
interface PersonContext {
  $implicit: string;
  age: number;
}

@Directive({
  selector: 'ng-template[person]',
  standalone: true,
})
export class PersonDirective {
  static ngTemplateContextGuard(
    dir: PersonDirective,
    ctx: unknown
  ): ctx is PersonContext {
    return true;
  }
}

```
We apply this directive on our template and that's it, we have a correct type inference.
 
![Correct IDE type inference](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evunp8vq7elcnxwvsqle.png)

However what about our directive? How can we apply strict type checking by passing our context? We can see in the image below that our compiler doesn't complain when we pass wrong property to our context. 

> **Remark:** as this time of writing, ngTemplateOutlet is not strictly typed and I'm using my own directive for the following part. _(You can find the code here)_.

![templateOutlet definition with wrong context and no compiler error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffqb5o2axpjmkq5g6yup.png)


This part is a bit trickier because we need to get our template reference in order to get our context.

On our previous article, `@ContentChild` decorator's `read` meta property was doing this part for us. Now we have to do it ourself. 

To do this, we will first inject our template reference inside our directive with the correct **context**. And to get that reference from outside, Angular exposes the `exportAs` option on the directive decorator. 

> `exportAs` defines a name that can be used from the template.

```typescript
@Directive({
  selector: 'ng-template[person]',
  exportAs: 'personExportAsRef', // named this way for better clarity
  standalone: true,
})
export class PersonDirective {
  constructor(public template: TemplateRef<PersonContext>){}

  static ngTemplateContextGuard(
    dir: PersonDirective,
    ctx: unknown
  ): ctx is PersonContext {
    return true;
  }
}
```

Now we can export our directive inside our template and have access to its public internal properties. 

```html
<ng-container
  *ngTemplateOutlet="
    personRef.template; <!-- ref to directive TemplateRef -->
    context: { $implicit: person.name,  age: person.age }
  ">
</ng-container>

<!-- assign the directive to personRef to access internal properties -->
<ng-template #personRef="personExportAsRef" person let-name let-age="age">
  {{ name }}: {{ age }}
</ng-template>
```

Now, the compiler is complaining if the property is of the wrong type or if one context property is missing. 

![compiler error on context wrong type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3t3frhjg2xthk922dt4.png)


![compiler error on context missing params](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z30w3sip624mrhz7ucg2.png)

---

**NgTemplateOutlet** and **Directives** should have no more secret for you. You can now create nice and secure application for your teammates. 

If you haven't read all related articles, I invite you to do it :
- [Typescript Type Predicate](https://dev.to/this-is-angular/typescript-type-predicate-3gbn)
- [Directive Type Checking](https://dev.to/this-is-angular/directive-type-checking-45oe)
- [NgTemplateOutlet Type Checking - with @ContentChild](https://dev.to/this-is-angular/ngtemplateoutlet-typed-checked-with-contentchild-2phe)

---

I hope you learned new Angular concept. If you liked it, you can find me on [Medium](https://medium.com/@thomas.laforge), [Twitter](https://twitter.com/laforge_toma) or [Github](https://github.com/tomalaforge).

> **👉 And if you want to accelerate your Angular learning journey, come and check out [Angular challenges](https://github.com/tomalaforge/angular-challenges).**