Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid creating _base declarations #61087

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 7 additions & 11 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1657,38 +1657,34 @@ export function transformDeclarations(context: TransformationContext): Transform

const extendsClause = getEffectiveBaseTypeNode(input);
if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) {
// We must add a temporary declaration for the extends clause expression
// For classes which get their base type from an expression other than a name or Null, replace the expression they extend with one of the form:
// declare class A extends ({} as DEFINITION_OF_BASE_HERE) {}

const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default";
const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic);
getSymbolAccessibilityDiagnostic = () => ({
diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
errorNode: extendsClause,
typeName: input.name,
});
const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, symbolTracker), /*initializer*/ undefined);
const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const));
const baseType = resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, declarationEmitInternalNodeBuilderFlags, symbolTracker);
const extendsExpression = factory.createAsExpression(factory.createObjectLiteralExpression(), baseType!); // TODO: GH#18217
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having never worked on this code before, and the relevant types and methods mostly being undocumented, I don't know why this createTypeOfExpression might return undefined or if ignoring undefined values here is safe to do here.

I'm also not sure if putting the // TODO: GH#18217 makes sense or not: it seemed to be used to track questionable use of ! (like the one I removed below) so I left it here to help draw attention to the ! here.

const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => {
if (clause.token === SyntaxKind.ExtendsKeyword) {
const oldDiag = getSymbolAccessibilityDiagnostic;
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]);
const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree, isTypeNode))));
const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, extendsExpression, visitNodes(t.typeArguments, visitDeclarationSubtree, isTypeNode))));
getSymbolAccessibilityDiagnostic = oldDiag;
return newClause;
}
return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree, isExpressionWithTypeArguments));
}));
return [
statement,
cleanup(factory.updateClassDeclaration(
return cleanup(factory.updateClassDeclaration(
input,
modifiers,
input.name,
typeParameters,
heritageClauses,
members,
))!,
]; // TODO: GH#18217
));
}
else {
const heritageClauses = transformHeritageClauses(input.heritageClauses);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ declare module "Configurable" {
declare module "Class" {
export class HiddenClass {
}
const ActualClass_base: typeof HiddenClass;
export class ActualClass extends ActualClass_base {
export class ActualClass extends ({} as typeof HiddenClass) {
}
}
5 changes: 2 additions & 3 deletions tests/baselines/reference/anonClassDeclarationEmitIsAnon.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,10 @@ export default _default;
export declare class User {
name: string;
}
declare const TimestampedUser_base: {
export declare class TimestampedUser extends ({} as {
new (...args: any[]): {
timestamp: number;
};
} & typeof User;
export declare class TimestampedUser extends TimestampedUser_base {
} & typeof User) {
constructor();
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ type OutputFrom<TFields> = {
[K in keyof TFields]: "_TOutput" extends keyof TFields[K] ? TFields[K]["_TOutput"] : never;
};
declare function string(): Type<string>;
declare const A_base: Class<OutputFrom<{
export declare class A extends ({} as Class<OutputFrom<{
a: typeof string;
}>>;
export declare class A extends A_base {
}>>) {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,10 @@ type MixinHelperFunc = <A extends AnyConstructor, T>(required: [A], arg: T) => T
export declare const Mixin: MixinHelperFunc;
export declare class Base {
}
declare const XmlElement2_base: {
export declare class XmlElement2 extends ({} as {
new (): {
num: number;
};
};
export declare class XmlElement2 extends XmlElement2_base {
}) {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,5 @@ declare class C<T, U> {
y: U;
}
declare function getClass<T>(c: T): typeof C;
declare const MyClass_base: typeof C;
declare class MyClass extends MyClass_base<string, number> {
declare class MyClass extends ({} as typeof C)<string, number> {
}
12 changes: 4 additions & 8 deletions tests/baselines/reference/declarationEmitExpressionInExtends3.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,12 @@ export interface ExportedInterface {
interface LocalInterface {
x: number;
}
declare const MyClass_base: typeof LocalClass;
export declare class MyClass extends MyClass_base<string, number> {
export declare class MyClass extends ({} as typeof LocalClass)<string, number> {
}
declare const MyClass2_base: typeof ExportedClass;
export declare class MyClass2 extends MyClass2_base<string> {
export declare class MyClass2 extends ({} as typeof ExportedClass)<string> {
}
declare const MyClass3_base: typeof ExportedClass;
export declare class MyClass3 extends MyClass3_base<LocalInterface> {
export declare class MyClass3 extends ({} as typeof ExportedClass)<LocalInterface> {
}
declare const MyClass4_base: typeof ExportedClass;
export declare class MyClass4 extends MyClass4_base<ExportedInterface> {
export declare class MyClass4 extends ({} as typeof ExportedClass)<ExportedInterface> {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,11 @@ var C3 = /** @class */ (function (_super) {
declare function getSomething(): {
new (): {};
};
declare const C_base: {
declare class C extends ({} as {
new (): {};
};
declare class C extends C_base<number, string> {
})<number, string> {
}
declare const C2_base: any;
declare class C2 extends C2_base<number, string> {
declare class C2 extends ({} as any)<number, string> {
}
declare class C3 extends SomeUndefinedFunction {
}
10 changes: 4 additions & 6 deletions tests/baselines/reference/declarationEmitExpressionInExtends5.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,11 @@ var Test;

//// [declarationEmitExpressionInExtends5.d.ts]
declare namespace Test {
export interface IFace {
interface IFace {
}
export class SomeClass implements IFace {
class SomeClass implements IFace {
}
const Derived_base: new () => IFace;
export class Derived extends Derived_base {
class Derived extends ({} as new () => IFace) {
}
export function getClass<T>(): new () => T;
export {};
function getClass<T>(): new () => T;
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ interface Greeter {
interface GreeterConstructor {
new (): Greeter;
}
declare const default_base: GreeterConstructor;
export default class extends default_base {
export default class extends ({} as GreeterConstructor) {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,9 @@ export declare const Mixed: {
bar: number;
};
} & typeof Unmixed;
declare const FilteredThing_base: (abstract new (...args: any[]) => {
export declare class FilteredThing extends ({} as (abstract new (...args: any[]) => {
match(path: string): boolean;
thing: number;
}) & typeof Unmixed;
export declare class FilteredThing extends FilteredThing_base {
}) & typeof Unmixed) {
match(path: string): boolean;
}
export {};
16 changes: 6 additions & 10 deletions tests/baselines/reference/declarationNoDanglingGenerics.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,24 @@ exports.CKind = CKind;


//// [declarationNoDanglingGenerics.d.ts]
declare const AKind_base: {
export declare class AKind extends ({} as {
new (): {
readonly kind: "A";
};
readonly THE_KIND: "A";
};
export declare class AKind extends AKind_base {
}) {
}
declare const BKind_base: {
export declare class BKind extends ({} as {
new (): {
readonly kind: "B";
};
readonly THE_KIND: "B";
};
export declare class BKind extends BKind_base {
}) {
}
declare const CKind_base: {
export declare class CKind extends ({} as {
new (): {
readonly kind: "C";
};
readonly THE_KIND: "C";
};
export declare class CKind extends CKind_base {
}) {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,12 @@ export declare function WithTags<T extends Constructor<FooItem>>(Base: T): {
};
getTags(): void;
} & T;
declare const Test_base: {
export declare class Test extends ({} as {
new (...args: any[]): {
tags(): void;
foo(): void;
name?: string;
};
getTags(): void;
} & typeof FooItem;
export declare class Test extends Test_base {
} & typeof FooItem) {
}
export {};
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,8 @@ export declare function MyMixin<T extends Constructor<MyBaseClass<any>>>(base: T
//// [FinalClass.d.ts]
import { MyBaseClass } from './BaseClass';
import { MyMixin } from './MixinClass';
declare const MyExtendedClass_base: typeof MyBaseClass & import("./BaseClass").Constructor<MyMixin>;
export declare class MyExtendedClass extends MyExtendedClass_base<string> {
export declare class MyExtendedClass extends ({} as typeof MyBaseClass & import("./BaseClass").Constructor<MyMixin>)<string> {
extendedClassProperty: number;
}
export {};
//// [Main.d.ts]
export {};
6 changes: 2 additions & 4 deletions tests/baselines/reference/mixinAbstractClasses.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,10 @@ declare class ConcreteBase {
declare abstract class AbstractBase {
abstract abstractBaseMethod(): void;
}
declare const DerivedFromConcrete_base: typeof ConcreteBase & (abstract new (...args: any) => Mixin);
declare class DerivedFromConcrete extends DerivedFromConcrete_base {
declare class DerivedFromConcrete extends ({} as typeof ConcreteBase & (abstract new (...args: any) => Mixin)) {
}
declare const wasConcrete: DerivedFromConcrete;
declare const DerivedFromAbstract_base: typeof AbstractBase & (abstract new (...args: any) => Mixin);
declare class DerivedFromAbstract extends DerivedFromAbstract_base {
declare class DerivedFromAbstract extends ({} as typeof AbstractBase & (abstract new (...args: any) => Mixin)) {
abstractBaseMethod(): void;
}
declare const wasAbstract: DerivedFromAbstract;
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ declare function Mixin2<TBase extends abstract new (...args: any[]) => any>(base
}) & {
staticMixinMethod(): void;
}) & TBase;
declare const DerivedFromAbstract2_base: ((abstract new (...args: any[]) => {
declare class DerivedFromAbstract2 extends ({} as ((abstract new (...args: any[]) => {
[x: string]: any;
mixinMethod(): void;
}) & {
staticMixinMethod(): void;
}) & typeof AbstractBase;
declare class DerivedFromAbstract2 extends DerivedFromAbstract2_base {
}) & typeof AbstractBase) {
abstractBaseMethod(): void;
}
18 changes: 6 additions & 12 deletions tests/baselines/reference/mixinAccessModifiers.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,27 +360,21 @@ declare function f4(x: Protected & Protected2): void;
declare function f5(x: Protected & Public): void;
declare function f6(x: Public & Public2): void;
declare function Mix<T, U>(c1: T, c2: U): T & U;
declare const C1_base: typeof Private & typeof Private2;
declare class C1 extends C1_base {
declare class C1 extends ({} as typeof Private & typeof Private2) {
}
declare const C2_base: typeof Private & typeof Protected;
declare class C2 extends C2_base {
declare class C2 extends ({} as typeof Private & typeof Protected) {
}
declare const C3_base: typeof Private & typeof Public;
declare class C3 extends C3_base {
declare class C3 extends ({} as typeof Private & typeof Public) {
}
declare const C4_base: typeof Protected & typeof Protected2;
declare class C4 extends C4_base {
declare class C4 extends ({} as typeof Protected & typeof Protected2) {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}
declare const C5_base: typeof Protected & typeof Public;
declare class C5 extends C5_base {
declare class C5 extends ({} as typeof Protected & typeof Public) {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}
declare const C6_base: typeof Public & typeof Public2;
declare class C6 extends C6_base {
declare class C6 extends ({} as typeof Public & typeof Public2) {
f(c4: C4, c5: C5, c6: C6): void;
static g(): void;
}
Expand Down
5 changes: 2 additions & 3 deletions tests/baselines/reference/override1.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,12 @@ declare function f(): {
bar(v: string): void;
};
};
declare const E_base: {
declare class E extends ({} as {
new (): {
foo(): void;
bar(): void;
};
};
declare class E extends E_base {
}) {
foo(): void;
bar(): void;
baz(): void;
Expand Down
10 changes: 4 additions & 6 deletions tests/baselines/reference/recursiveClassBaseType.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,16 @@ declare const p: <T>(fn: () => T) => T;
declare const Base: <T>(val: T) => {
new (): T;
};
declare const C_base: new () => {
declare class C extends ({} as new () => {
x: C[];
};
declare class C extends C_base {
}) {
}
declare abstract class Base1 {
abstract root(): Derived1;
}
declare const Derived1_base: {
declare class Derived1 extends ({} as {
new (): {
root(): any;
};
};
declare class Derived1 extends Derived1_base {
}) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,9 @@ exports.Sub = Sub;
//# sourceMappingURL=main.js.map

//// [D:/Work/pkg1/dist/main.d.ts]
declare const Sub_base: import("./utils/type-helpers").MyReturnType;
export declare class Sub extends Sub_base {
export declare class Sub extends ({} as import("./utils/type-helpers").MyReturnType) {
id: string;
}
export {};



Expand Down
Loading