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?