Skip to content
This repository has been archived by the owner on Dec 5, 2022. It is now read-only.

Renamed types that have the same name as a variable, but aren't directly related #67

Merged
merged 2 commits into from
Nov 23, 2019
Merged
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
22 changes: 18 additions & 4 deletions lib/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,18 +381,32 @@ export function normalizeSourceFile(
const statement = n;
statement.declarationList.declarations.forEach((variableDecl: ts.VariableDeclaration) => {
if (ts.isIdentifier(variableDecl.name)) {
const name = base.ident(variableDecl.name);
if (variableDecl.type) {
const variableType = variableDecl.type;

// Try to find a Constructor within the variable's type.
const constructor: base.Constructor = findConstructorInType(variableType);
// If we cannot find a constructor within the variable's type, we still need to check
// whether or not a type with the same name as the variable already exists. If it does,
// we must rename it. That type is not directly associated with this variable, so they
// cannot be combined.
if (!constructor) {
if (classes.has(name)) {
const existing = classes.get(name);
if (!ts.isInterfaceDeclaration(existing)) {
return;
}
const clonedName = ts.getMutableClone(existing.name);
clonedName.escapedText = ts.escapeLeadingUnderscores(name + 'Interface');
existing.name = clonedName;
}
return;
}

// Get the type of object that the constructor creates.
const constructedType = getConstructedObjectType(constructor);
if (!constructedType) {
return;
}

const name = base.ident(variableDecl.name);
if (classes.has(name)) {
const existing = classes.get(name);
// If a class with the same name as the variable already exists, we should suppress
Expand Down
39 changes: 36 additions & 3 deletions test/declaration_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,10 +1162,13 @@ class X {

// End module m1`);
});
});

// Case where we cannot find a variable matching the interface so it is unsafe to give the
// interface a constructor.
expectTranslate(`
describe('cases where a type and a variable cannot be merged', () => {
it('should handle cases where an interface has no matching variable', () => {
// Case where we cannot find a variable matching the interface so it is unsafe to give the
// interface a constructor.
expectTranslate(`
interface X {
new (a: string|bool, b: number): XType;
}`).to.equal(`@anonymous
Expand All @@ -1174,6 +1177,36 @@ abstract class X {
// Constructors on anonymous interfaces are not yet supported.
/*external factory X(String|bool a, num b);*/
}`);
});

it('should handle cases where a type and a variable have the same name but are unrelated',
() => {
// Case where a variable has the same name as a type, but they should not be combined
// because they are unrelated. This is valid in TypeScript because the variable has an
// actual value in JavaScript, whereas the type is only part of TypeScript's type system.
expectTranslate(`
interface X {
a: string;
b: number;
c(): boolean;
}

declare var X: { a: number[], b: number[], c: number[] };
`).to.equal(`@anonymous
@JS()
abstract class XInterface {
derekxu16 marked this conversation as resolved.
Show resolved Hide resolved
external String get a;
external set a(String v);
external num get b;
external set b(num v);
external bool c();
}

@JS()
external dynamic /*{ a: number[], b: number[], c: number[] }*/ get X;
@JS()
external set X(dynamic /*{ a: number[], b: number[], c: number[] }*/ v);`);
});
});
});

Expand Down