-
Notifications
You must be signed in to change notification settings - Fork 57
Description
I'm providing glint support for ember-element-helper
tildeio/ember-element-helper#107
Here are the types based on the ones from Dan (in tildeio/ember-element-helper#102):
export type ElementFromTagName<T extends string> = T extends keyof HTMLElementTagNameMap
? HTMLElementTagNameMap[T]
: Element;
type Positional<T extends string> = [name: T];
type Return<T extends string> = typeof EmberComponent<{
Element: ElementFromTagName<T>;
Blocks: { default: [] };
}>;
export interface ElementSignature<T extends string> {
Args: {
Positional: Positional<T>;
};
Return: Return<T> | undefined;
}
export default class ElementHelper<T extends string> extends Helper<ElementSignature<T>> {}
Using the helper works straight away:
<template>
{{#let (element 'div') as |Tag|}}
<Tag id="lalala" ...attributes>Hello there!</Tag>
{{/let}}
</template>
Going a bit more dynamic and allowing a @tag
to be passed in, works when the type is made explicit:
import { type ElementSignature } from 'ember-element-helper';
interface ElementReceiverSignature{
Element: HTMLDivElement; // 1: explicit element here
Args: {
tag: ElementSignature<'div'>['Return']; // 2: explicit tag name here
};
Blocks: {
default: [];
};
}
export default class ElementReceiver extends Component<ElementReceiverSignature> {
<template>
{{#let @tag as |Tag|}}
<Tag id="content" ...attributes>{{yield}}</Tag>
{{/let}}
</template>
}
... of course those explicit types do not make sense, when we want to have any element being passed in. Making it generic makes the problem visible:
import {
type ElementFromTagName,
type ElementSignature
} from 'ember-element-helper';
interface ElementReceiverSignature<T extends string> {
Element: ElementFromTagName<T>;
Args: {
tag: ElementSignature<T>['Return'];
};
Blocks: {
default: [];
};
}
export default class ElementReceiver<T extends string> extends Component<
ElementReceiverSignature<T>
> {
<template>
{{#let @tag as |Tag|}}
<Tag id="content" ...attributes>{{yield}}</Tag>
{{/let}}
</template>
}
This reveals two locations where glint throws both times the same error:
<Tag
and...attributes
Wit the error message being:
Argument of type 'NonNullable<ElementFromTagName<T>> extends never ? unknown :
ElementFromTagName<T>' is not assignable to parameter of type 'Element'.
Type 'unknown' is not assignable to type 'Element'.glint(2345)
As to my understanding, the types for the signature are correct, but the error message is wrong. The ElementFromTagName
will always return a valid type, in either explicit HTMLElementTagNameMap[T]
or generic Element
which should be accurate inside the component (typing the unknownigly character of @tag
).
Is this a valid problem with glint? Or are my typings wrong?