From 427d43691a4fa74325fa843cbdd1cc9c9b89e215 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 1 Aug 2022 10:57:38 -0700 Subject: [PATCH] Improve import type support for commonjs exports (#49745) * Improve import type support for commonjs exports This PR makes getTypeFromImportTypeNode a little more like getExternalModuleMember: for JS files, it now uses both `getTypeOfSymbol` and `getExportsOfSymbol`, and uses whichever one returns a symbol. This allows using arbitrary properties of a CJS export= as types in JSDoc; previously a special case in the binder enabled only CJS export= where all properties were shorthand assignments. Fixes #49195 * Add js types/value test case * Improve binding of CJS property assignments 1. Bind property assignments same as shorthand property assignments in module.exports object literal assignments. 2. Bind all such assignments, even if the object literal contains non-property assignments. This is different from before, and it requires slightly smarter code to prefer aliases when checking CJS imports. * Remove new binder code Just include the original fix * revert missed type in binder --- src/compiler/checker.ts | 16 +- .../moduleExportAssignment7.errors.txt | 92 +++++++ .../reference/moduleExportAssignment7.symbols | 195 ++++++++++++++ .../reference/moduleExportAssignment7.types | 249 ++++++++++++++++++ .../salsa/moduleExportAssignment7.ts | 69 +++++ 5 files changed, 612 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/moduleExportAssignment7.errors.txt create mode 100644 tests/baselines/reference/moduleExportAssignment7.symbols create mode 100644 tests/baselines/reference/moduleExportAssignment7.types create mode 100644 tests/cases/conformance/salsa/moduleExportAssignment7.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a6f21c13f82..cd2254c87b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3099,11 +3099,6 @@ namespace ts { return getNodeLinks(expression).resolvedSymbol; } - function getTargetOfPropertyAssignment(node: PropertyAssignment, dontRecursivelyResolve: boolean): Symbol | undefined { - const expression = node.initializer; - return getTargetOfAliasLikeExpression(expression, dontRecursivelyResolve); - } - function getTargetOfAccessExpression(node: AccessExpression, dontRecursivelyResolve: boolean): Symbol | undefined { if (!(isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken)) { return undefined; @@ -3136,7 +3131,7 @@ namespace ts { case SyntaxKind.ShorthandPropertyAssignment: return resolveEntityName((node as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontRecursivelyResolve); case SyntaxKind.PropertyAssignment: - return getTargetOfPropertyAssignment(node as PropertyAssignment, dontRecursivelyResolve); + return getTargetOfAliasLikeExpression((node as PropertyAssignment).initializer, dontRecursivelyResolve); case SyntaxKind.ElementAccessExpression: case SyntaxKind.PropertyAccessExpression: return getTargetOfAccessExpression(node as AccessExpression, dontRecursivelyResolve); @@ -9353,7 +9348,7 @@ namespace ts { } (resolvedSymbol || symbol).exports!.forEach((s, name) => { const exportedMember = members.get(name)!; - if (exportedMember && exportedMember !== s) { + if (exportedMember && exportedMember !== s && !(s.flags & SymbolFlags.Alias)) { if (s.flags & SymbolFlags.Value && exportedMember.flags & SymbolFlags.Value) { // If the member has an additional value-like declaration, union the types from the two declarations, // but issue an error if they occurred in two different files. The purpose is to support a JS file with @@ -16298,6 +16293,7 @@ namespace ts { links.resolvedSymbol = unknownSymbol; return links.resolvedType = errorType; } + const isExportEquals = !!innerModuleSymbol.exports?.get(InternalSymbolName.ExportEquals); const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false); if (!nodeIsMissing(node.qualifier)) { const nameStack: Identifier[] = getIdentifierChain(node.qualifier!); @@ -16309,9 +16305,11 @@ namespace ts { // That, in turn, ultimately uses `getPropertyOfType` on the type of the symbol, which differs slightly from // the `exports` lookup process that only looks up namespace members which is used for most type references const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); - const next = node.isTypeOf + const symbolFromVariable = node.isTypeOf || isInJSFile(node) && isExportEquals ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) - : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); + : undefined; + const symbolFromModule = node.isTypeOf ? undefined : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); + const next = symbolFromModule ?? symbolFromVariable; if (!next) { error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); return links.resolvedType = errorType; diff --git a/tests/baselines/reference/moduleExportAssignment7.errors.txt b/tests/baselines/reference/moduleExportAssignment7.errors.txt new file mode 100644 index 00000000000..1bf25e6ca33 --- /dev/null +++ b/tests/baselines/reference/moduleExportAssignment7.errors.txt @@ -0,0 +1,92 @@ +tests/cases/conformance/salsa/index.ts(2,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'Thing'. +tests/cases/conformance/salsa/index.ts(3,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'AnotherThing'. +tests/cases/conformance/salsa/index.ts(4,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'foo'. +tests/cases/conformance/salsa/index.ts(5,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'qux'. +tests/cases/conformance/salsa/index.ts(6,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'baz'. +tests/cases/conformance/salsa/index.ts(8,24): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'literal'. +tests/cases/conformance/salsa/index.ts(19,31): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'buz'. +tests/cases/conformance/salsa/main.js(20,35): error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'buz'. + + +==== tests/cases/conformance/salsa/mod.js (0 errors) ==== + class Thing { x = 1 } + class AnotherThing { y = 2 } + function foo() { return 3 } + function bar() { return 4 } + /** @typedef {() => number} buz */ + module.exports = { + Thing, + AnotherThing, + foo, + qux: bar, + baz() { return 5 }, + literal: "", + } +==== tests/cases/conformance/salsa/main.js (1 errors) ==== + /** + * @param {import("./mod").Thing} a + * @param {import("./mod").AnotherThing} b + * @param {import("./mod").foo} c + * @param {import("./mod").qux} d + * @param {import("./mod").baz} e + * @param {import("./mod").buz} f + * @param {import("./mod").literal} g + */ + function jstypes(a, b, c, d, e, f, g) { + return a.x + b.y + c() + d() + e() + f() + g.length + } + + /** + * @param {typeof import("./mod").Thing} a + * @param {typeof import("./mod").AnotherThing} b + * @param {typeof import("./mod").foo} c + * @param {typeof import("./mod").qux} d + * @param {typeof import("./mod").baz} e + * @param {typeof import("./mod").buz} f + ~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'buz'. + * @param {typeof import("./mod").literal} g + */ + function jsvalues(a, b, c, d, e, f, g) { + return a.length + b.length + c() + d() + e() + f() + g.length + } + +==== tests/cases/conformance/salsa/index.ts (7 errors) ==== + function types( + a: import('./mod').Thing, + ~~~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'Thing'. + b: import('./mod').AnotherThing, + ~~~~~~~~~~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'AnotherThing'. + c: import('./mod').foo, + ~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'foo'. + d: import('./mod').qux, + ~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'qux'. + e: import('./mod').baz, + ~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'baz'. + f: import('./mod').buz, + g: import('./mod').literal, + ~~~~~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'literal'. + ) { + return a.x + b.y + c() + d() + e() + f() + g.length + } + + function values( + a: typeof import('./mod').Thing, + b: typeof import('./mod').AnotherThing, + c: typeof import('./mod').foo, + d: typeof import('./mod').qux, + e: typeof import('./mod').baz, + f: typeof import('./mod').buz, + ~~~ +!!! error TS2694: Namespace '"tests/cases/conformance/salsa/mod".export=' has no exported member 'buz'. + g: typeof import('./mod').literal, + ) { + return a.length + b.length + c() + d() + e() + f() + g.length + } + \ No newline at end of file diff --git a/tests/baselines/reference/moduleExportAssignment7.symbols b/tests/baselines/reference/moduleExportAssignment7.symbols new file mode 100644 index 00000000000..35ff7fca3d1 --- /dev/null +++ b/tests/baselines/reference/moduleExportAssignment7.symbols @@ -0,0 +1,195 @@ +=== tests/cases/conformance/salsa/mod.js === +class Thing { x = 1 } +>Thing : Symbol(Thing, Decl(mod.js, 0, 0)) +>x : Symbol(Thing.x, Decl(mod.js, 0, 14)) + +class AnotherThing { y = 2 } +>AnotherThing : Symbol(AnotherThing, Decl(mod.js, 0, 22)) +>y : Symbol(AnotherThing.y, Decl(mod.js, 1, 20)) + +function foo() { return 3 } +>foo : Symbol(foo, Decl(mod.js, 1, 29)) + +function bar() { return 4 } +>bar : Symbol(bar, Decl(mod.js, 2, 27)) + +/** @typedef {() => number} buz */ +module.exports = { +>module.exports : Symbol(module.exports, Decl(mod.js, 0, 0)) +>module : Symbol(export=, Decl(mod.js, 3, 27)) +>exports : Symbol(export=, Decl(mod.js, 3, 27)) + + Thing, +>Thing : Symbol(Thing, Decl(mod.js, 5, 18)) + + AnotherThing, +>AnotherThing : Symbol(AnotherThing, Decl(mod.js, 6, 10)) + + foo, +>foo : Symbol(foo, Decl(mod.js, 7, 17)) + + qux: bar, +>qux : Symbol(qux, Decl(mod.js, 8, 8)) +>bar : Symbol(bar, Decl(mod.js, 2, 27)) + + baz() { return 5 }, +>baz : Symbol(baz, Decl(mod.js, 9, 13)) + + literal: "", +>literal : Symbol(literal, Decl(mod.js, 10, 23)) +} +=== tests/cases/conformance/salsa/main.js === +/** + * @param {import("./mod").Thing} a + * @param {import("./mod").AnotherThing} b + * @param {import("./mod").foo} c + * @param {import("./mod").qux} d + * @param {import("./mod").baz} e + * @param {import("./mod").buz} f + * @param {import("./mod").literal} g + */ +function jstypes(a, b, c, d, e, f, g) { +>jstypes : Symbol(jstypes, Decl(main.js, 0, 0)) +>a : Symbol(a, Decl(main.js, 9, 17)) +>b : Symbol(b, Decl(main.js, 9, 19)) +>c : Symbol(c, Decl(main.js, 9, 22)) +>d : Symbol(d, Decl(main.js, 9, 25)) +>e : Symbol(e, Decl(main.js, 9, 28)) +>f : Symbol(f, Decl(main.js, 9, 31)) +>g : Symbol(g, Decl(main.js, 9, 34)) + + return a.x + b.y + c() + d() + e() + f() + g.length +>a.x : Symbol(Thing.x, Decl(mod.js, 0, 14)) +>a : Symbol(a, Decl(main.js, 9, 17)) +>x : Symbol(Thing.x, Decl(mod.js, 0, 14)) +>b.y : Symbol(AnotherThing.y, Decl(mod.js, 1, 20)) +>b : Symbol(b, Decl(main.js, 9, 19)) +>y : Symbol(AnotherThing.y, Decl(mod.js, 1, 20)) +>c : Symbol(c, Decl(main.js, 9, 22)) +>d : Symbol(d, Decl(main.js, 9, 25)) +>e : Symbol(e, Decl(main.js, 9, 28)) +>f : Symbol(f, Decl(main.js, 9, 31)) +>g.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>g : Symbol(g, Decl(main.js, 9, 34)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + +/** + * @param {typeof import("./mod").Thing} a + * @param {typeof import("./mod").AnotherThing} b + * @param {typeof import("./mod").foo} c + * @param {typeof import("./mod").qux} d + * @param {typeof import("./mod").baz} e + * @param {typeof import("./mod").buz} f + * @param {typeof import("./mod").literal} g + */ +function jsvalues(a, b, c, d, e, f, g) { +>jsvalues : Symbol(jsvalues, Decl(main.js, 11, 1)) +>a : Symbol(a, Decl(main.js, 22, 18)) +>b : Symbol(b, Decl(main.js, 22, 20)) +>c : Symbol(c, Decl(main.js, 22, 23)) +>d : Symbol(d, Decl(main.js, 22, 26)) +>e : Symbol(e, Decl(main.js, 22, 29)) +>f : Symbol(f, Decl(main.js, 22, 32)) +>g : Symbol(g, Decl(main.js, 22, 35)) + + return a.length + b.length + c() + d() + e() + f() + g.length +>a.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(main.js, 22, 18)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>b.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(main.js, 22, 20)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(main.js, 22, 23)) +>d : Symbol(d, Decl(main.js, 22, 26)) +>e : Symbol(e, Decl(main.js, 22, 29)) +>f : Symbol(f, Decl(main.js, 22, 32)) +>g.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>g : Symbol(g, Decl(main.js, 22, 35)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + +=== tests/cases/conformance/salsa/index.ts === +function types( +>types : Symbol(types, Decl(index.ts, 0, 0)) + + a: import('./mod').Thing, +>a : Symbol(a, Decl(index.ts, 0, 15)) + + b: import('./mod').AnotherThing, +>b : Symbol(b, Decl(index.ts, 1, 29)) + + c: import('./mod').foo, +>c : Symbol(c, Decl(index.ts, 2, 36)) + + d: import('./mod').qux, +>d : Symbol(d, Decl(index.ts, 3, 27)) + + e: import('./mod').baz, +>e : Symbol(e, Decl(index.ts, 4, 27)) + + f: import('./mod').buz, +>f : Symbol(f, Decl(index.ts, 5, 27)) +>buz : Symbol(buz, Decl(mod.js, 4, 4)) + + g: import('./mod').literal, +>g : Symbol(g, Decl(index.ts, 6, 27)) + +) { + return a.x + b.y + c() + d() + e() + f() + g.length +>a : Symbol(a, Decl(index.ts, 0, 15)) +>b : Symbol(b, Decl(index.ts, 1, 29)) +>c : Symbol(c, Decl(index.ts, 2, 36)) +>d : Symbol(d, Decl(index.ts, 3, 27)) +>e : Symbol(e, Decl(index.ts, 4, 27)) +>f : Symbol(f, Decl(index.ts, 5, 27)) +>g : Symbol(g, Decl(index.ts, 6, 27)) +} + +function values( +>values : Symbol(values, Decl(index.ts, 10, 1)) + + a: typeof import('./mod').Thing, +>a : Symbol(a, Decl(index.ts, 12, 16)) +>Thing : Symbol(Thing, Decl(mod.js, 5, 18)) + + b: typeof import('./mod').AnotherThing, +>b : Symbol(b, Decl(index.ts, 13, 36)) +>AnotherThing : Symbol(AnotherThing, Decl(mod.js, 6, 10)) + + c: typeof import('./mod').foo, +>c : Symbol(c, Decl(index.ts, 14, 43)) +>foo : Symbol(foo, Decl(mod.js, 7, 17)) + + d: typeof import('./mod').qux, +>d : Symbol(d, Decl(index.ts, 15, 34)) +>qux : Symbol(qux, Decl(mod.js, 8, 8)) + + e: typeof import('./mod').baz, +>e : Symbol(e, Decl(index.ts, 16, 34)) +>baz : Symbol(baz, Decl(mod.js, 9, 13)) + + f: typeof import('./mod').buz, +>f : Symbol(f, Decl(index.ts, 17, 34)) + + g: typeof import('./mod').literal, +>g : Symbol(g, Decl(index.ts, 18, 34)) +>literal : Symbol(literal, Decl(mod.js, 10, 23)) + +) { + return a.length + b.length + c() + d() + e() + f() + g.length +>a.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(index.ts, 12, 16)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>b.length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(index.ts, 13, 36)) +>length : Symbol(Function.length, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(index.ts, 14, 43)) +>d : Symbol(d, Decl(index.ts, 15, 34)) +>e : Symbol(e, Decl(index.ts, 16, 34)) +>f : Symbol(f, Decl(index.ts, 17, 34)) +>g.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>g : Symbol(g, Decl(index.ts, 18, 34)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/moduleExportAssignment7.types b/tests/baselines/reference/moduleExportAssignment7.types new file mode 100644 index 00000000000..da89258952f --- /dev/null +++ b/tests/baselines/reference/moduleExportAssignment7.types @@ -0,0 +1,249 @@ +=== tests/cases/conformance/salsa/mod.js === +class Thing { x = 1 } +>Thing : Thing +>x : number +>1 : 1 + +class AnotherThing { y = 2 } +>AnotherThing : AnotherThing +>y : number +>2 : 2 + +function foo() { return 3 } +>foo : () => number +>3 : 3 + +function bar() { return 4 } +>bar : () => number +>4 : 4 + +/** @typedef {() => number} buz */ +module.exports = { +>module.exports = { Thing, AnotherThing, foo, qux: bar, baz() { return 5 }, literal: "",} : { Thing: typeof Thing; AnotherThing: typeof AnotherThing; foo: () => number; qux: () => number; baz(): number; literal: string; } +>module.exports : { Thing: typeof Thing; AnotherThing: typeof AnotherThing; foo: () => number; qux: () => number; baz(): number; literal: string; } +>module : { exports: { Thing: typeof Thing; AnotherThing: typeof AnotherThing; foo: () => number; qux: () => number; baz(): number; literal: string; }; } +>exports : { Thing: typeof Thing; AnotherThing: typeof AnotherThing; foo: () => number; qux: () => number; baz(): number; literal: string; } +>{ Thing, AnotherThing, foo, qux: bar, baz() { return 5 }, literal: "",} : { Thing: typeof Thing; AnotherThing: typeof AnotherThing; foo: () => number; qux: () => number; baz(): number; literal: string; } + + Thing, +>Thing : typeof Thing + + AnotherThing, +>AnotherThing : typeof AnotherThing + + foo, +>foo : () => number + + qux: bar, +>qux : () => number +>bar : () => number + + baz() { return 5 }, +>baz : () => number +>5 : 5 + + literal: "", +>literal : string +>"" : "" +} +=== tests/cases/conformance/salsa/main.js === +/** + * @param {import("./mod").Thing} a + * @param {import("./mod").AnotherThing} b + * @param {import("./mod").foo} c + * @param {import("./mod").qux} d + * @param {import("./mod").baz} e + * @param {import("./mod").buz} f + * @param {import("./mod").literal} g + */ +function jstypes(a, b, c, d, e, f, g) { +>jstypes : (a: Thing, b: AnotherThing, c: () => number, d: () => number, e: () => number, f: import("./mod").buz, g: string) => number +>a : Thing +>b : AnotherThing +>c : () => number +>d : () => number +>e : () => number +>f : import("tests/cases/conformance/salsa/mod").buz +>g : string + + return a.x + b.y + c() + d() + e() + f() + g.length +>a.x + b.y + c() + d() + e() + f() + g.length : number +>a.x + b.y + c() + d() + e() + f() : number +>a.x + b.y + c() + d() + e() : number +>a.x + b.y + c() + d() : number +>a.x + b.y + c() : number +>a.x + b.y : number +>a.x : number +>a : Thing +>x : number +>b.y : number +>b : AnotherThing +>y : number +>c() : number +>c : () => number +>d() : number +>d : () => number +>e() : number +>e : () => number +>f() : number +>f : import("tests/cases/conformance/salsa/mod").buz +>g.length : number +>g : string +>length : number +} + +/** + * @param {typeof import("./mod").Thing} a + * @param {typeof import("./mod").AnotherThing} b + * @param {typeof import("./mod").foo} c + * @param {typeof import("./mod").qux} d + * @param {typeof import("./mod").baz} e + * @param {typeof import("./mod").buz} f + * @param {typeof import("./mod").literal} g + */ +function jsvalues(a, b, c, d, e, f, g) { +>jsvalues : (a: typeof import("./mod").Thing, b: typeof import("./mod").AnotherThing, c: typeof import("./mod").foo, d: typeof import("./mod").qux, e: typeof import("./mod").baz, f: any, g: typeof import("./mod").literal) => any +>a : typeof Thing +>b : typeof AnotherThing +>c : () => number +>d : () => number +>e : () => number +>f : any +>g : string + + return a.length + b.length + c() + d() + e() + f() + g.length +>a.length + b.length + c() + d() + e() + f() + g.length : any +>a.length + b.length + c() + d() + e() + f() : any +>a.length + b.length + c() + d() + e() : number +>a.length + b.length + c() + d() : number +>a.length + b.length + c() : number +>a.length + b.length : number +>a.length : number +>a : typeof Thing +>length : number +>b.length : number +>b : typeof AnotherThing +>length : number +>c() : number +>c : () => number +>d() : number +>d : () => number +>e() : number +>e : () => number +>f() : any +>f : any +>g.length : number +>g : string +>length : number +} + +=== tests/cases/conformance/salsa/index.ts === +function types( +>types : (a: any, b: any, c: any, d: any, e: any, f: import('./mod').buz, g: any) => any + + a: import('./mod').Thing, +>a : any + + b: import('./mod').AnotherThing, +>b : any + + c: import('./mod').foo, +>c : any + + d: import('./mod').qux, +>d : any + + e: import('./mod').baz, +>e : any + + f: import('./mod').buz, +>f : import("tests/cases/conformance/salsa/mod").buz + + g: import('./mod').literal, +>g : any + +) { + return a.x + b.y + c() + d() + e() + f() + g.length +>a.x + b.y + c() + d() + e() + f() + g.length : any +>a.x + b.y + c() + d() + e() + f() : any +>a.x + b.y + c() + d() + e() : any +>a.x + b.y + c() + d() : any +>a.x + b.y + c() : any +>a.x + b.y : any +>a.x : any +>a : any +>x : any +>b.y : any +>b : any +>y : any +>c() : any +>c : any +>d() : any +>d : any +>e() : any +>e : any +>f() : number +>f : import("tests/cases/conformance/salsa/mod").buz +>g.length : any +>g : any +>length : any +} + +function values( +>values : (a: typeof import('./mod').Thing, b: typeof import('./mod').AnotherThing, c: typeof import('./mod').foo, d: typeof import('./mod').qux, e: typeof import('./mod').baz, f: any, g: typeof import('./mod').literal) => any + + a: typeof import('./mod').Thing, +>a : typeof Thing +>Thing : any + + b: typeof import('./mod').AnotherThing, +>b : typeof AnotherThing +>AnotherThing : any + + c: typeof import('./mod').foo, +>c : () => number +>foo : any + + d: typeof import('./mod').qux, +>d : () => number +>qux : any + + e: typeof import('./mod').baz, +>e : () => number +>baz : any + + f: typeof import('./mod').buz, +>f : any +>buz : any + + g: typeof import('./mod').literal, +>g : string +>literal : any + +) { + return a.length + b.length + c() + d() + e() + f() + g.length +>a.length + b.length + c() + d() + e() + f() + g.length : any +>a.length + b.length + c() + d() + e() + f() : any +>a.length + b.length + c() + d() + e() : number +>a.length + b.length + c() + d() : number +>a.length + b.length + c() : number +>a.length + b.length : number +>a.length : number +>a : typeof Thing +>length : number +>b.length : number +>b : typeof AnotherThing +>length : number +>c() : number +>c : () => number +>d() : number +>d : () => number +>e() : number +>e : () => number +>f() : any +>f : any +>g.length : number +>g : string +>length : number +} + diff --git a/tests/cases/conformance/salsa/moduleExportAssignment7.ts b/tests/cases/conformance/salsa/moduleExportAssignment7.ts new file mode 100644 index 00000000000..1e73f7bbb48 --- /dev/null +++ b/tests/cases/conformance/salsa/moduleExportAssignment7.ts @@ -0,0 +1,69 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @Filename: mod.js +class Thing { x = 1 } +class AnotherThing { y = 2 } +function foo() { return 3 } +function bar() { return 4 } +/** @typedef {() => number} buz */ +module.exports = { + Thing, + AnotherThing, + foo, + qux: bar, + baz() { return 5 }, + literal: "", +} +// @Filename: main.js +/** + * @param {import("./mod").Thing} a + * @param {import("./mod").AnotherThing} b + * @param {import("./mod").foo} c + * @param {import("./mod").qux} d + * @param {import("./mod").baz} e + * @param {import("./mod").buz} f + * @param {import("./mod").literal} g + */ +function jstypes(a, b, c, d, e, f, g) { + return a.x + b.y + c() + d() + e() + f() + g.length +} + +/** + * @param {typeof import("./mod").Thing} a + * @param {typeof import("./mod").AnotherThing} b + * @param {typeof import("./mod").foo} c + * @param {typeof import("./mod").qux} d + * @param {typeof import("./mod").baz} e + * @param {typeof import("./mod").buz} f + * @param {typeof import("./mod").literal} g + */ +function jsvalues(a, b, c, d, e, f, g) { + return a.length + b.length + c() + d() + e() + f() + g.length +} + +// @Filename: index.ts + +function types( + a: import('./mod').Thing, + b: import('./mod').AnotherThing, + c: import('./mod').foo, + d: import('./mod').qux, + e: import('./mod').baz, + f: import('./mod').buz, + g: import('./mod').literal, +) { + return a.x + b.y + c() + d() + e() + f() + g.length +} + +function values( + a: typeof import('./mod').Thing, + b: typeof import('./mod').AnotherThing, + c: typeof import('./mod').foo, + d: typeof import('./mod').qux, + e: typeof import('./mod').baz, + f: typeof import('./mod').buz, + g: typeof import('./mod').literal, +) { + return a.length + b.length + c() + d() + e() + f() + g.length +}