FontAwesome 6 with Angular 18: Argument of type 'IconDefinition' is not assignable to parameter of type 'IconName | IconLookup'

3 min read 27-08-2024
FontAwesome 6 with Angular 18: Argument of type 'IconDefinition' is not assignable to parameter of type 'IconName | IconLookup'


The error message "Argument of type 'IconDefinition' is not assignable to parameter of type 'IconName | IconLookup'" is a common one when working with FontAwesome 6 and Angular. It arises due to changes in the library's structure and type definitions between versions. This article will guide you through understanding the issue and provide a solution.

Understanding the Issue

The core of the problem lies in the way FontAwesome 6 manages icon definitions and the way Angular interacts with them. Prior to FontAwesome 6, icons were primarily represented as strings (e.g., 'fa-user'). FontAwesome 6 introduced a more structured IconDefinition type to represent icons, containing information like the icon name, prefix, and other metadata. Angular, when handling icons, expects these icons to be either a simple string name (like 'fa-user') or a more complex IconLookup object (which has 'prefix' and 'iconName' properties).

The issue arises when you try to pass an IconDefinition object (created by FontAwesome 6) to functions expecting either a string name or a IconLookup.

The Solution: Using faIconLibrary

The solution involves utilizing the FaIconLibrary service provided by the @fortawesome/angular-fontawesome package. Here's a breakdown:

  1. Import FaIconLibrary: Ensure you have the following import in your component or service:

    import { FaIconLibrary } from '@fortawesome/angular-fontawesome';
    
  2. Inject FaIconLibrary: Inject the FaIconLibrary service into your component's constructor:

    constructor(private faIconLibrary: FaIconLibrary) {}
    
  3. Retrieve Icon Definitions: Instead of directly passing an IconDefinition to functions like iconFunc (from @fortawesome/fontawesome-svg-core), use faIconLibrary.getIconDefinition to get an appropriate IconLookup object:

    import { faCoffee, faUser } from '@fortawesome/free-solid-svg-icons';
    
    public static getLiteralSvg(faIconLibrary: FaIconLibrary, icon: IconDefinition): string {
        const iconLookup = faIconLibrary.getIconDefinition(icon.prefix, icon.iconName);
        return iconFunc(iconLookup).html.join('');
    }
    
  4. Update Usage: When using functions that expect a string name or IconLookup, ensure you retrieve the appropriate IconLookup object using faIconLibrary.getIconDefinition as demonstrated above.

Example:

Here's a complete example with the RegisterFontIcons class updated to use faIconLibrary:

import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import {
  FaIconLibrary,
  IconDefinition,
  IconName,
  IconPrefix,
} from '@fortawesome/angular-fontawesome';
import { icon as iconFunc } from '@fortawesome/fontawesome-svg-core';

export class RegisterFontIcons {
  public static registerMaterialIcons(iconRegistry: MatIconRegistry) {
    // Register the material icon styles
    iconRegistry.registerFontClassAlias(
      'outlined',
      'mat-ligature-font material-icons material-icons-outlined',
    );
  }

  public static registerFontAwesomIcons(iconRegistry: MatIconRegistry) {
    // Set default font set to Font Awesome Solid icons for non-SVG icons
    iconRegistry.setDefaultFontSetClass('fa-solid');
  }

  public static registerFontAwesomSvgIcons(
    iconRegistry: MatIconRegistry,
    sanitizer: DomSanitizer,
    faIconLibrary: FaIconLibrary,
    icons: IconDefinition[],
  ) {
    icons.forEach((icon: IconDefinition) => {
      // console.log(icon.prefix, icon.iconName);
      const svg: SafeHtml = RegisterFontIcons.getLiteralSafeSvg(faIconLibrary, sanitizer, icon);
      if (icon.prefix === 'fas') {
        iconRegistry.addSvgIconLiteral(icon.iconName, svg);
      } else {
        // Only use a namespace for the non-solid icons
        iconRegistry.addSvgIconLiteralInNamespace(icon.prefix, icon.iconName, svg);
      }
    });
  }

  public static getLiteralSvg(faIconLibrary: FaIconLibrary, icon: IconDefinition): string {
    const iconLookup = faIconLibrary.getIconDefinition(icon.prefix, icon.iconName);
    return iconFunc(iconLookup).html.join('');
  }

  public static getLiteralSafeSvg(
    faIconLibrary: FaIconLibrary,
    sanitizer: DomSanitizer,
    icon: IconDefinition
  ): SafeHtml {
    const iconLookup = faIconLibrary.getIconDefinition(icon.prefix, icon.iconName);
    return sanitizer.bypassSecurityTrustHtml(iconFunc(iconLookup).html.join(''));
  }

  public static getFontAwesomeIcon(
    faIconLibrary: FaIconLibrary,
    prefix: IconPrefix,
    name: IconName,
  ): IconDefinition {
    return faIconLibrary.getIconDefinition(prefix, name);
  }
}

Conclusion

By using the FaIconLibrary service to retrieve the correct IconLookup representation for each icon, you can seamlessly integrate FontAwesome 6 into your Angular 18 project. Remember to import and inject the service correctly and use faIconLibrary.getIconDefinition when working with icon functions that expect string names or IconLookup objects.