The TypeScript documentation about writing subclassable components mentions writing a MyList<T>
component that accepts any child Component of type T.
Next to this, another usecase is about writing a flexible base component, MyBaseComponent<TemplateSpecType, TypeConfig>
. It has a basic code sample, which describes how to set it up.
I’m interested in the first usecase, but I’m having troubles setting it up. What I’m looking for is the structure of a base page, which includes a Header
& Content
component. And I would like to use generics to ensure type checking.
This is my current code:
interface IPageTemplateSpec extends Lightning.Component.TemplateSpec {
Header: typeof Header;
Content: object;
}
interface IPageTypeConfig extends Lightning.Component.TypeConfig {
IsPage: true;
}
class Page
extends Lightning.Component<IPageTemplateSpec, IPageTypeConfig>
implements Lightning.Component.ImplementTemplateSpec<IPageTemplateSpec>
{
static override _template(): Lightning.Component.Template<IPageTemplateSpec> {
return {
w: (w: number) => w,
h: (h: number) => h,
rect: true,
color: 0xff0e0e0e,
Header: {
type: Header,
},
Content: {},
};
}
protected Content = this.getByRef("Content")!;
}
Then I create a child Discovery
page which extends the base Page
:
export class Discovery extends Page {
static override _template(): Lightning.Component.Template<IPageTemplateSpec> {
const pageTemplate = super._template();
return pageTemplate;
}
}
Then I apply generics to the IPageTemplateSpec
interface, in order to use any child component like this:
interface IPageTemplateSpec<T extends Lightning.Component = Lightning.Component>
extends Lightning.Component.TemplateSpec {
Header: typeof Header;
Content: T;
}
class Page<T extends Lightning.Component = Lightning.Component>
extends Lightning.Component<IPageTemplateSpec<T>, IPageTypeConfig>
implements Lightning.Component.ImplementTemplateSpec<IPageTemplateSpec<T>>
{
static override _template(): Lightning.Component.Template<
IPageTemplateSpec<Lightning.Component>
> {
return {
w: (w: number) => w,
h: (h: number) => h,
rect: true,
color: 0xff0e0e0e,
Header: {
type: Header,
},
Content: {},
};
}
protected Content = this.getByRef("Content")!;
}
export class Discovery extends Page<List> {
static override _template(): Lightning.Component.Template<
IPageTemplateSpec<List>
> {
const pageTemplate = super._template();
pageTemplate.Content = {
type: List,
};
return pageTemplate;
}
}
With this code I get 2 errors:
- line
protected Content = this.getByRef("Content")!
shows:
Argument of type ‘string’ is not assignable to parameter of type ‘keyof TemplateSpecRefs<IPageTemplateSpec>’.
Type ‘“Content”’ is not assignable to type ‘“Header” | (TransformPossibleElement<P, IPageTemplateSpec[P], never> extends never ? never : P) | ((T extends Constructor<…> ? InstanceType<…> : Element<…>) extends never ? never : “Content”)’.ts(2345) - line
pageTemplate.Content = { type: List, };
shows:
*Type ‘{ type: any; }’ is not assignable to type Template<CompileElementTemplateSpecType<InlineElement<Component<TemplateSpecLoose, TypeConfig>>, TypeConfig>>'.
Object literal may only specify known properties, and ‘type’ does not exist in type 'Template<CompileElementTemplateSpecType<InlineElement<Component<TemplateSpecLoose, TypeConfig>>, TypeConfig>>.
What am I not doing correct in here?