Currently, I am developing stimulus controllers in TypeScript and I can't help but wonder if there is a more efficient way to declare all the properties like has*Target
, *Target
, and *Targets
. It feels tedious to declare each one individually.
Is there a better approach that achieves what I'm aiming for? Any insights would be greatly appreciated. Thank you!
Below is some code snippet that I have been experimenting with in an attempt to make it work:
import { Controller } from '@hotwired/stimulus';
namespace Transform {
export type HasTarget<T> = {
[K in keyof T as `has${Capitalize<string & K>}Target`]: boolean;
};
export type Target<T> = {
[K in keyof T as `${string & K}Target`]: T[K];
};
export type Targets<T> = {
[K in keyof T as `${string & K}Targets`]: Array<T[K]>;
};
}
const targets = [
'button',
'container',
] as const;
type TargetList = typeof targets;
interface Targets extends Record<TargetList[number], HTMLElement> {
button: HTMLButtonElement;
container: HTMLDivElement;
}
type ControllerWithTarget<T> =
& Transform.HasTarget<T>
& Transform.Target<T>
& Transform.Targets<T>;
// Attempting to achieve something similar to this
export default class extends Controller implements ControllerWithTarget<Targets> {
static targets = [...targets];
// declare readonly hasButtonTarget: boolean;
// declare readonly buttonTarget: HTMLButtonElement;
// declare readonly buttonTargets: Array<HTMLButtonElement>;
// declare readonly hasContainerTarget: boolean;
// declare readonly containerTarget: HTMLDivElement;
// declare readonly containerTargets: Array<HTMLDivElement>;
disableButton(): void {
if ( this.hasButtonTarget ) {
this.buttonTarget.disabled = true;
}
}
}
UPDATE The compiler is showing an error message:
Class 'default' incorrectly implements interface 'ControllerWithTarget<Targets>'.