ember-cli / ember-template-imports

Template import support in Ember!
MIT License
74 stars 39 forks source link

Yielding of advanced components #240

Closed BwehaaFox closed 3 hours ago

BwehaaFox commented 4 months ago

Adapting old components to the import mechanics, I was glad to note that the component helper works well with imports, but there were questions about typing

For context, the BlockHTMLSignature interface implements a shortcut for the standard signature structure, in fact [{ icon: typeof Icon }] is the default block definition.

If you try to pass the imported component directly to the block, there are no problems

import Icon from './ui/icon';
export default class extends Component<BlockHTMLSignature<Args, [{ icon: typeof Icon }]>> {
  <template>
    {{yield (hash icon=Icon)}}
  </template>
}

But if necessary, set the default values ​​"as before", through the component helper:

import Icon from './ui/icon';
export default class extends Component<BlockHTMLSignature<Args, [{ icon: typeof Icon }]>> {
  <template>
    {{#let (component Icon inline_shift=true)  as |ModIcon|}}
      {{yield (hash icon=ModIcon)}}
    {{/let}}
  </template>
}

A warning appears:

Type 'Invokable<(named?: PrebindArgs<{ inline_shift?: boolean; ... | ... 179 more ...  } & NamedArgsMarker,...' is not assignable to type 'typeof Icon'.
  Cannot assign an abstract constructor type to a non-abstract constructor type.glint(2322)

The question is: is there another specialized helper for such a situation, or is there an alternative new way of passing an extended component, or is it necessary to somehow modify the definition of defaults: [{ icon: typeof Icon }] for such cases with some existing interface or specific signature?

NullVoxPopuli commented 4 months ago

what's the type of BlockHTMLSignature ?

BwehaaFox commented 4 months ago

As I wrote above, just "shortcut"

declare interface HTMLSignature<T extends {} = {}> {
  Args: {
    [key in keyof T]: T[key]
  };
  Element: HTMLElement;
}

declare interface BlockHTMLSignature<J extends {} = {}, T extends Object | any[] = any[]> extends HTMLSignature<J> {
  Blocks: T extends any[] ? {
    default: T
  } : {
    [key in keyof T]: T[key]
  } 
}
BwehaaFox commented 3 hours ago

Solution found here As a result, there really is a special type WithBoundArgs to solve this problem

import { WithBoundArgs } from '@glint/template';
import Icon from './ui/icon';
export default class extends Component<BlockHTMLSignature<Args, [{ icon: WithBoundArgs<typeof Icon, 'inline_shift'> }]>> {
  <template>
    {{#let (component Icon inline_shift=true)  as |ModIcon|}}
      {{yield (hash icon=ModIcon)}}
    {{/let}}
  </template>
}

This way the error disappears