Dynamically declare `*Target` properties with TS
mlwyatt opened this issue · comments
I've looked over #121 and #466 and while they are similar, they aren't quite what I'm looking for. I know when using TS I need to declare
the *Target
properties I want to use. I'm fine with that but I'm wondering if that can done dynamically.
declare
ing all of the properties isn't too bad when there's only 1 or 2 targets
, but sometimes I have numerous targets
and would like to avoid declare
ing every one of them when they're all very similar. It's a similar situation for values
and outlets
but I use those far less than targets
Is there a way to dynamically declare
these properties or to tell TS that Controller
does correctly implement ControllerWithTarget<Targets>
below (while avoiding @ts-ignore
and similar) ?
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>;
// Trying to achieve something like 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;
}
}
}
Any help is greatly appreciated, thanks!
Hey @mlwyatt, I know this might not be exactly what you are looking for, but I find the pattern proposed in the stimulus-decorators
package kinda elegant.
Hey @mlwyatt, I know this might not be exactly what you are looking for, but I find the pattern proposed in the
stimulus-decorators
package kinda elegant.
Thanks for reaching out! I agree that it's elegant but it's also a bit outdated (no support for outlets) and not quite what I'm after. I think what I want just isn't possible with the current state of TS
@mlwyatt give this a go