Is it possible to make a re-usable icon component that doesn't create duplicate TemplateRefs
Indeed, although working, this approach looks a bit heavy, because for each new SVG template the icon.component.html file will need to be changed and a respective TemplateRef field has to be created in the component.
It is not clear from the example, but if in your task all the pieces of SVG are static (not generated through the app logic), it can be solved differently. Here are some hints:

for each SVG template, create a file under the application resources: chevron.svg, tick.svg etc, with the respective contents.

in icon.component.ts, add a getter returning the path to the SVG file, for example:


public get svgResourcePath(): string {
  return `/path/to/resource/${this.icon}.svg`;
}


change the icon.component.html, so that it uses a standard HTML image tag, with the value of the src attribute bound to the path:

&lt;img [src]=&quot;svgResourcePath&quot;/&gt;

Update

One point I didn't put in my question is that I also need to bind a color to the SVG through an @Input().

As I've mentioned, it was not clear from the initial question. But still there is a solution for that, although it looks a bit longer than my previous suggestion.
I've played a bit and implemented it here.
The ideas behind the approach:

Since SVG code can be included directly in a component template, we can create separate component definitions for all necessary cases, e.g. for tick:

@Component({
  selector: &quot;tick-icon&quot;, // does not matter, because we do not intend to insert it through a template
  template: `
    &lt;svg&gt;
      &lt;path
        [attr.fill]=&quot;fillColor&quot;
        d=&quot;M23.9 3.7L9.7 17.9l-6.8-6.8-2.8 2.6 9.7 9.6L26.7 6.5z&quot;
      /&gt;
    &lt;/svg&gt;
  `
})
export class TickComponent implements StyleConfigurable {
  private _fillColor: string;

  @Input()
  public set fillColor(fc: string) {
    this._fillColor = fc;
  }

  public get fillColor(): string {
    return this._fillColor;
  }
}

The StyleConfigurable interface here is an interface that defines the SVG styling properties that we want to customize:
export interface StyleConfigurable {
  fillColor: string;
}


Angular components can be instantiated dynamically, so we adjust the algo from the doc for our use case:

export class IconComponent implements OnInit {
  private _icon: string;

  private _fillColor: string;

  // inject the necessary objects for the dynamic instantiation:
  public constructor(
    private _resolver: ComponentFactoryResolver,
    private _containerRef: ViewContainerRef
  ) {}

  public ngOnInit(): void {
    // trigger the SVG icons loading when this component is initialized:
    this.loadIcon();
  }

  // dynamically load the icon:
  private loadIcon(): void {
    const cmpFactory = this._resolver.resolveComponentFactory(this.getTypeForIcon());
    const cmpRef = this._containerRef.createComponent&lt;StyleConfigurable&gt;(
      cmpFactory
    );
    // note this call: instance.fillColor is available through StyleConfigurable
    cmpRef.instance.fillColor = this._fillColor;
  }

  // for each supported value of the 'icon' property, return the corresponding component type:
  private getTypeForIcon(): Type&lt;StyleConfigurable&gt; {
    switch (this._icon) {
      case &quot;tick&quot;:
        return TickComponent;
      case &quot;chevron&quot;:
        return ChevronComponent;
      default:
        throw Error(`Unrecognized icon: ${this._icon}`);
    }
  }
}

Now the IconComponent can be used as follows:
&lt;app-icon icon=&quot;chevron&quot; fillColor=&quot;rgb(0, 255, 0)&quot;&gt;&lt;/app-icon&gt;
&lt;app-icon icon=&quot;tick&quot; fillColor=&quot;rgb(255, 0, 0)&quot;&gt;&lt;/app-icon&gt;