What's new in Angular 17.3
Tags: angular, typescript, signals, javascript
Published: 2024-03-18 07:09:14

---
title: What's new in Angular 17.3
published: true
tags: #angular #typescript #signals #javascript
canonical_url: https://www.angularaddicts.com/p/whats-new-in-angular-17-3
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86wfs8rsxtzcpnktf6j6.png
---

Since I published my [Master Angular 17 Study guide](https://www.angularaddicts.com/p/master-angular-17) and [Master Angular 17.1 and 17.2 Study guide](https://www.angularaddicts.com/p/master-angular-17-1-and-17-2), the Angular team released a new minor version: **17.3**.

## 🎯Changes and new features
In this article, I list out the most important changes and new features, also share resources that will teach you how these new Angular features work:

- `output()` API for emitting output from a component
- `outputFromObservable()` helper function for transforming an observable to a component's  `output()`
- `outputToObservable()` helper function for converting a component's output to an observable
- `hostAttributeToken()` class, it creates a token that can be used to inject static attributes of the host node
- Typescript 5.4 support

### 📌New `output()` API
Official docs: [output](https://next.angular.io/api/core/output)
PR: [Finalizing output() and outputFromObservable() APIs](https://github.com/angular/angular/pull/54650)

Angular 17.3 introduced the new `output()` API, for emitting output from a component. This API is designed to complement the `input()` and `model()` APIs, and it's type safe:

```ts
@Component({
  selector: 'app-output',
  standalone: true,
  template: `
    <button (click)="onClick.emit()">Button</button>
    <input #in type="text" (keyup)="onChange.emit(in.value)" />
  `,
})
export class OutputComponent {
  onClick = output();          // 👈 OutputEmitterRef<void>
  onChange = output<string>(); // 👈 OutputEmitterRef<string>
}

@Component({
  selector: 'app-output-wrapper',
  standalone: true,
  imports: [OutputComponent],
  template: ` <app-output (onClick)="log('onClick')" (onChange)="log('onChange', $event)" /> `,
})
export class OutputWrapperComponent {
  log(t1: string, t2: string = '') { console.log(t1, t2); }
}

// after you click on the button, then type 'test' into the input field, 
// the messages on the console are:
// onClick 
// onChange t
// onChange te
// onChange tes
// onChange test
```

### 📌`outputFromObservable()` and `outputToObservable` helper functions
Official docs: [outputFromObservable](https://next.angular.io/api/core/rxjs-interop/outputFromObservable), [outputToObservable](https://next.angular.io/api/core/rxjs-interop/outputToObservable)
PR: [Finalizing output() and outputFromObservable() APIs](https://github.com/angular/angular/pull/54650)

In addition the new `output()` API, Angular 17.3 also contains the `outputFromObservable()` helper function for transforming an observable to a component's `output()`:

```ts

@Component({
  selector: 'app-output2',
  standalone: true,
  template: `<button (click)="onClick$.next('click2')">Button</button>`,
})
export class Output2Component {
  onClick$ = new BehaviorSubject(''); // 👈 BehaviorSubject<string>
  onClick = outputFromObservable(this.onClick$); // 👈 OutputRef<string>
}

@Component({
  selector: 'app-output-wrapper2',
  standalone: true,
  imports: [Output2Component],
  template: `<app-output2 (onClick)="log('onClick', $event)" />`,
})
export class OutputWrapper2Component {
  log(t1: string, t2: string = '') { console.log(t1, t2); }
}

// after you click on the button, the message on the console is:
// onClick click2
```

There is also a `outputToObservable()` helper function for converting a component's output to an observable:

```ts

@Component({
  selector: 'app-output3',
  standalone: true,
  template: `<button (click)="onClick.emit()">Button</button>`,
})
export class Output3Component {
  onClick = output(); // 👈 OutputEmitterRef<void>
}

@Component({
  selector: 'app-output-wrapper3',
  standalone: true,
  imports: [Output3Component],
  template: `<app-output3/>`, // 👈 no (onClick)="..." here!
})
export class OutputWrapper3Component implements OnInit {
  childComponent = viewChild(Output3Component);
  destroyRef = inject(DestroyRef);
  
  ngOnInit(): void {
    const childComponent = this.childComponent();
    if (childComponent) {
      const onClick$ = outputToObservable(childComponent.onClick) // 👈 
        .pipe(takeUntilDestroyed(this.destroyRef));
      onClick$.subscribe(() => console.log('onClick'));
    }
  }
}

// after you click on the button, the message on the console is:
// onClick
```

### 📌`HostAttributeToken()` class
Official docs: [HostAttributeToken](https://next.angular.io/api/core/HostAttributeToken)
PR: [feat(core): add API to inject attributes on the host node](https://github.com/angular/angular/pull/54604)

The `HostAttributeToken()` class creates a token that can be used to inject static attributes of the host node. It works similarly to `constructor(@Attribute('value') type: string)`, but uses the newer `inject()` API instead of the `@Attribute` decorator. 

```ts
@Component({
  selector: 'app-hat',
  standalone: true,
  template: `<div>{{ value }}</div>
    <div>{{ value2 }}</div>`,
})
export class HatComponent {
  // 👇 required, we get a DI error if the attribute is not specified
  value = inject(new HostAttributeToken('value'));
  // 👇 optional attribute
  value2 = inject(new HostAttributeToken('value2'), 
    { optional: true }) || 'Default value';
}

@Component({
  selector: 'app-hat-wrapper',
  standalone: true,
  imports: [HatComponent],
  //    we don't specify the optional 'value2' attribute, 
  // 👇 so its value is 'Default value' 
  template: `<app-hat value="Hello" />`,
})
export class HatWrapperComponent {}
```

[In his article](https://netbasal.com/streamlining-attribute-injection-in-angular-the-hostattributetoken-approach-494f5c1428b8), [Netanel Basal](https://twitter.com/NetanelBasal) explains in more details how this new feature works.

### 📌Typescript 5.4 support
PR: [feat(core): support TypeScript 5.4](https://github.com/angular/angular/pull/54414)

[Daniel Rosenwasser](https://twitter.com/drosenwasser) highlighted the most interesting new features of Typescript 5.4 in his [announcement](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/):

- Preserved Narrowing in Closures Following Last Assignments
- The `NoInfer` Utility Type
- `Object.groupBy` and `Map.groupBy`
- Support for `require()` calls in `--moduleResolution bundler` and `--module preserve`
- Checked Import Attributes and Assertions
- Quick Fix for Adding Missing Parameters
- Auto-Import Support for Subpath Imports

## 👨‍💻About the author

My name is [Gergely Szerovay](https://www.linkedin.com/in/gergelyszerovay/), I work as a frontend development chapter lead. Teaching (and learning) Angular is one of my passions. I consume content related to Angular on a daily basis — articles, podcasts, conference talks, you name it.

I created the Angular Addict Newsletter so that I can send you the best resources I come across each month. Whether you are a seasoned Angular Addict or a beginner, I got you covered.

Next to the newsletter, I also have a publication called [Angular Addicts](https://angularaddicts.com/). It is a collection of the resources I find most informative and interesting. Let me know if you would like to be included as a writer.

Let’s learn Angular together! [Subscribe here](https://www.angularaddicts.com/) 🔥

Follow me on [Substack](https://www.angularaddicts.com/), [Medium](https://medium.com/@GergelySzerovay), [Dev.to](https://dev.to/gergelyszerovay), [Twitter](https://twitter.com/GergelySzerovay) or [LinkedIn](https://www.linkedin.com/in/gergelyszerovay/) to learn more about Angular!