Skip to content

Commit e9f3e48

Browse files
authored
Feat/add type parameters to class name
feat: add type parameters to class name
1 parent 22d9858 commit e9f3e48

File tree

9 files changed

+334
-441
lines changed

9 files changed

+334
-441
lines changed

src/compiler/build/build-stats.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ function getComponentsFileMap(config: d.Config, buildCtx: d.BuildCtx) {
146146
source: relativePath(config, component.sourceFilePath),
147147
elementRef: component.elementRef,
148148
componentClassName: component.componentClassName,
149+
componentClassTypeParameters: component.componentClassTypeParameters,
149150
assetsDirs: component.assetsDirs,
150151
dependencies: component.dependencies,
151152
dependents: component.dependents,

src/compiler/transformers/static-to-meta/component.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const parseStaticComponentMeta = (
4545
excludeFromCollection: moduleFile.excludeFromCollection,
4646
isCollectionDependency,
4747
componentClassName: cmpNode.name ? cmpNode.name.text : '',
48+
componentClassTypeParameters: [],
4849
elementRef: parseStaticElementRef(staticMembers),
4950
encapsulation,
5051
shadowDelegatesFocus: parseStaticShadowDelegatesFocus(encapsulation, staticMembers),
@@ -119,6 +120,34 @@ export const parseStaticComponentMeta = (
119120
potentialCmpRefs: [],
120121
};
121122

123+
/**
124+
* This code add a component class name with the type
125+
* parameters. Later in the compiler execution there
126+
* will this name used to named the interfaces in the
127+
* component.d.ts.
128+
*
129+
* Addressed issue(s):
130+
* - https://github.com/ionic-team/stencil/issues/2895
131+
*
132+
* TypeScript implementation:
133+
* - https://github.com/microsoft/TypeScript/blob/7584e6aad6b21f7334562bfd9d8c3c80aafed064/src/services/services.ts#L326
134+
*/
135+
if (
136+
typeof symbol === 'object' &&
137+
symbol !== null &&
138+
typeof symbol.getDeclarations === 'function'
139+
) {
140+
const declarations = symbol.getDeclarations();
141+
if (Array.isArray(declarations) && declarations.length > 0) {
142+
const declaration = declarations[0] as ts.ClassDeclaration;
143+
if (Array.isArray(declaration.typeParameters)) {
144+
declaration.typeParameters.forEach((typeParameter) =>
145+
cmp.componentClassTypeParameters.push(typeParameter.name.text)
146+
);
147+
}
148+
}
149+
}
150+
122151
const visitComponentChildNode = (node: ts.Node) => {
123152
if (ts.isCallExpression(node)) {
124153
parseCallExpression(cmp, node);

src/compiler/types/generate-component-types.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ export const generateComponentTypes = (
1818
): d.TypesModule => {
1919
const tagName = cmp.tagName.toLowerCase();
2020
const tagNameAsPascal = dashToPascalCase(tagName);
21+
const classTypeParams =
22+
cmp.componentClassTypeParameters.length > 0 ? `<${cmp.componentClassTypeParameters.join(',')}>` : '';
23+
const classTypeParamsAny =
24+
cmp.componentClassTypeParameters.length > 0
25+
? `<${cmp.componentClassTypeParameters.map(() => 'any').join(',')}>`
26+
: '';
2127
const htmlElementName = `HTML${tagNameAsPascal}Element`;
2228

2329
const propAttributes = generatePropTypes(cmp, typeImportData);
@@ -33,20 +39,19 @@ export const generateComponentTypes = (
3339
const jsxAttributes = attributesToMultiLineString([...propAttributes, ...eventAttributes], true, areTypesInternal);
3440

3541
const element = [
36-
` interface ${htmlElementName} extends Components.${tagNameAsPascal}, HTMLStencilElement {`,
42+
` interface ${htmlElementName}${classTypeParams} extends Components.${tagNameAsPascal}${classTypeParams}, HTMLStencilElement {`,
43+
` prototype: ${htmlElementName}${classTypeParams};`,
44+
` new (): ${htmlElementName}${classTypeParams};`,
3745
` }`,
38-
` var ${htmlElementName}: {`,
39-
` prototype: ${htmlElementName};`,
40-
` new (): ${htmlElementName};`,
41-
` };`,
46+
` var ${htmlElementName}: ${htmlElementName}${classTypeParamsAny};`,
4247
];
4348
return {
4449
isDep,
4550
tagName,
46-
tagNameAsPascal,
47-
htmlElementName,
48-
component: ` interface ${tagNameAsPascal} {\n${componentAttributes} }`,
49-
jsx: ` interface ${tagNameAsPascal} {\n${jsxAttributes} }`,
51+
tagNameAsPascal: `${tagNameAsPascal}${classTypeParamsAny}`,
52+
htmlElementName: `${htmlElementName}${classTypeParamsAny}`,
53+
component: ` interface ${tagNameAsPascal}${classTypeParams} {\n${componentAttributes} }`,
54+
jsx: ` interface ${tagNameAsPascal}${classTypeParams} {\n${jsxAttributes} }`,
5055
element: element.join(`\n`),
5156
};
5257
};

src/compiler/types/tests/ComponentCompilerMeta.stub.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const stubComponentCompilerMeta = (
1212
): d.ComponentCompilerMeta => ({
1313
assetsDirs: [],
1414
componentClassName: 'StubCmp',
15+
componentClassTypeParameters: [],
1516
dependencies: [],
1617
dependents: [],
1718
directDependencies: [],

src/declarations/stencil-private.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ export interface ComponentCompilerFeatures {
778778
export interface ComponentCompilerMeta extends ComponentCompilerFeatures {
779779
assetsDirs: CompilerAssetDir[];
780780
componentClassName: string;
781+
componentClassTypeParameters: string[];
781782
elementRef: string;
782783
encapsulation: Encapsulation;
783784
shadowDelegatesFocus: boolean;

0 commit comments

Comments
 (0)