1

I have been experimenting with Angular 16, particularly with zoneless and signals, and I've accomplished some interesting stuff.

When working with component communication using @Input(), I found myself writing repetitive and cumbersome code like this:

@Input('foo') set fooSetter(value: number) {
    this.foo.set(value);
}
foo = signal(0);

The issue I encountered is not specific to Angular 16 or signals, but rather with the @Input() decorator itself. I want to create a reusable code wrapper for this functionality.

The desired outcome is something like this:

import { InputSignal } from './input-signal';

@Component({
  selector: 'app-foo',
    standalone: true,
    // ...
})
export class FooComponent {
  @InputSignal() foo = signal(0);
}

This would call '.set()' on the signal instead of overriding it, also, the angular lsp and compiler should recognize this input as a number instead of a signal.

My first try was to create a custom decorator that uses the @Input decorator to extend its functionality.

// input-signal.ts
import { Input } from "@angular/core"

export function InputSignal(...args: Parameters<typeof Input>): PropertyDecorator {
  return (target, key) => {
    const inputDecorate = Input(...args) as PropertyDecorator;
    const nativeInputKey = '__' + (getAlias(args) ?? String(key));
    inputDecorate(target, nativeInputKey);
    // More code...
  }
}

function getAlias([alias]: Parameters<typeof Input>): string | undefined {
  if (!alias) return undefined;
  if (typeof alias === 'string') return alias;

  return alias.alias;
}

Then, I checked it worked with the angular lsp and compiler, but, surprise, this error appeared:

NG8002: Can't bind to 'foo' since it isn't a known property of 'app-foo'.

My next try was to check if the custom decorators support by angular even exits.

import { Component, ChangeDetectionStrategy, Input, signal, computed } from '@angular/core';
import { Input2 } from './input2';

@Component({
  selector: 'app-foo',
    standalone: true,
    // ...
})
export class FooComponent {
  @Input2() foo = 2;
  // ...
}

Sadly, it did not work as well.

NG8002: Can't bind to 'foo' since it isn't a known property of 'app-foo'.

Questions:

  • Is there a way to interact with the Angular compiler to resolve this issue and make the custom decorator function as intended?

0 Answers0