diff --git a/packages/core/src/compiler/transformers/_test_/parse-extends.spec.ts b/packages/core/src/compiler/transformers/_test_/parse-extends.spec.ts index 7cee838dbd2..9ef067cebc8 100644 --- a/packages/core/src/compiler/transformers/_test_/parse-extends.spec.ts +++ b/packages/core/src/compiler/transformers/_test_/parse-extends.spec.ts @@ -185,4 +185,36 @@ describe('transpile() – cross-file class extension', () => { const propNames = cmp.properties.map((p: any) => p.name); expect(propNames.filter((n: string) => n === 'baseProp')).toHaveLength(1); }); + + it('resolves a base class declared in the same file (full-compiler path)', async () => { + const results = await transpile( + ` + import { Component, Prop, State, Method } from '@stencil/core'; + + class ExtendsBase { + @Prop() baseProp: string = 'base'; + @State() baseState: string = 'base'; + @Method() async baseMethod() {} + } + + @Component({ tag: 'my-component' }) + export class MyComponent extends ExtendsBase { + @Prop() ownProp: string = 'own'; + } + `, + { + file: join(fixturesDir, 'my-component.tsx'), + target: 'es2022', + currentDirectory: fixturesDir, + }, + ); + + expect(results.diagnostics).toHaveLength(0); + const cmp = results.data?.[0]; + expect(cmp).toBeDefined(); + expect(cmp.properties.map((p: any) => p.name)).toContain('ownProp'); + expect(cmp.properties.map((p: any) => p.name)).toContain('baseProp'); + expect(cmp.states.map((s: any) => s.name)).toContain('baseState'); + expect(cmp.methods.map((m: any) => m.name)).toContain('baseMethod'); + }); }); diff --git a/packages/core/src/compiler/transformers/static-to-meta/class-extension.ts b/packages/core/src/compiler/transformers/static-to-meta/class-extension.ts index c8e69d786e8..b53bb7c8f98 100644 --- a/packages/core/src/compiler/transformers/static-to-meta/class-extension.ts +++ b/packages/core/src/compiler/transformers/static-to-meta/class-extension.ts @@ -377,11 +377,13 @@ function buildExtendsTree( try { // happy path (normally 1 file level removed): the extends type resolves to a class declaration in another file - const symbol = typeChecker?.getSymbolAtLocation(extendee); - const aliasedSymbol = symbol ? typeChecker.getAliasedSymbol(symbol) : undefined; + let symbol = typeChecker?.getSymbolAtLocation(extendee); + if (symbol && symbol.flags & ts.SymbolFlags.Alias) { + symbol = typeChecker.getAliasedSymbol(symbol); + } - let source = aliasedSymbol?.declarations?.[0].getSourceFile(); - let declarations: ts.Declaration[] | ts.Statement[] = aliasedSymbol?.declarations; + let source = symbol?.declarations?.[0].getSourceFile(); + let declarations: ts.Declaration[] | ts.Statement[] = symbol?.declarations; if (source.fileName.endsWith('.d.ts')) { source = convertDtsToJs(source.fileName, compilerCtx);