Make direct assignments to cjs exports considered literal contexts (#39816)

* Make direct assignments to cjs exports considered literal contexts

* Style feedback from PR

* Trailing whitespaaaaace
This commit is contained in:
Wesley Wigham
2022-03-09 13:27:39 -08:00
committed by GitHub
parent f76452cb27
commit 3f63804878
35 changed files with 300 additions and 199 deletions
+17 -8
View File
@@ -7014,9 +7014,13 @@ namespace ts {
else {
// A Class + Property merge is made for a `module.exports.Member = class {}`, and it doesn't serialize well as either a class _or_ a property symbol - in fact, _it behaves like an alias!_
// `var` is `FunctionScopedVariable`, `const` and `let` are `BlockScopedVariable`, and `module.exports.thing =` is `Property`
const flags = !(symbol.flags & SymbolFlags.BlockScopedVariable) ? undefined
: isConstVariable(symbol) ? NodeFlags.Const
: NodeFlags.Let;
const flags = !(symbol.flags & SymbolFlags.BlockScopedVariable)
? symbol.parent?.valueDeclaration && isSourceFile(symbol.parent?.valueDeclaration)
? NodeFlags.Const // exports are immutable in es6, which is what we emulate and check; so it's safe to mark all exports as `const` (there's no difference to consumers, but it allows unique symbol type declarations)
: undefined
: isConstVariable(symbol)
? NodeFlags.Const
: NodeFlags.Let;
const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol);
let textRange: Node | undefined = symbol.declarations && find(symbol.declarations, d => isVariableDeclaration(d));
if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) {
@@ -9180,7 +9184,10 @@ namespace ts {
if (containsSameNamedThisProperty(expression.left, expression.right)) {
return anyType;
}
const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : getWidenedLiteralType(checkExpressionCached(expression.right));
const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression)));
const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol)
: isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right))
: getWidenedLiteralType(checkExpressionCached(expression.right));
if (type.flags & TypeFlags.Object &&
kind === AssignmentDeclarationKind.ModuleExports &&
symbol.escapedName === InternalSymbolName.ExportEquals) {
@@ -16418,9 +16425,11 @@ namespace ts {
function getESSymbolLikeTypeForNode(node: Node) {
if (isValidESSymbolDeclaration(node)) {
const symbol = getSymbolOfNode(node);
const links = getSymbolLinks(symbol);
return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol));
const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node);
if (symbol) {
const links = getSymbolLinks(symbol);
return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol));
}
}
return esSymbolType;
}
@@ -34209,7 +34218,7 @@ namespace ts {
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type {
const type = checkExpression(node, checkMode, forceTuple);
return isConstContext(node) ? getRegularTypeOfLiteralType(type) :
return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) :
isTypeAssertion(node) ? type :
getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node) : contextualType, node));
}
+14 -3
View File
@@ -1520,10 +1520,21 @@ namespace ts {
&& node.parent.parent.kind === SyntaxKind.VariableStatement;
}
export function isValidESSymbolDeclaration(node: Node): node is VariableDeclaration | PropertyDeclaration | SignatureDeclaration {
return isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) :
export function isCommonJsExportedExpression(node: Node) {
if (!isInJSFile(node)) return false;
return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) ||
isCommonJsExportPropertyAssignment(node.parent);
}
export function isCommonJsExportPropertyAssignment(node: Node) {
if (!isInJSFile(node)) return false;
return (isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty);
}
export function isValidESSymbolDeclaration(node: Node): boolean {
return (isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) :
isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) :
isPropertySignature(node) && hasEffectiveReadonlyModifier(node);
isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) || isCommonJsExportPropertyAssignment(node);
}
export function introducesArgumentsExoticObject(node: Node) {
@@ -13,5 +13,5 @@ exports.y = 2;
//// [assignmentToVoidZero1.d.ts]
export var x: number;
export var y: number;
export const x: 1;
export const y: 2;
@@ -2,27 +2,27 @@
// #38552
exports.y = exports.x = void 0;
>exports.y = exports.x = void 0 : undefined
>exports.y : number
>exports.y : 2
>exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1")
>y : number
>y : 2
>exports.x = void 0 : undefined
>exports.x : number
>exports.x : 1
>exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1")
>x : number
>x : 1
>void 0 : undefined
>0 : 0
exports.x = 1;
>exports.x = 1 : 1
>exports.x : number
>exports.x : 1
>exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1")
>x : number
>x : 1
>1 : 1
exports.y = 2;
>exports.y = 2 : 2
>exports.y : number
>exports.y : 2
>exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1")
>y : number
>y : 2
>2 : 2
@@ -41,6 +41,6 @@ assignmentToVoidZero2_1.j + assignmentToVoidZero2_1.k;
//// [assignmentToVoidZero2.d.ts]
export var j: number;
export const j: 1;
//// [importer.d.ts]
export {};
@@ -1,9 +1,9 @@
=== tests/cases/conformance/salsa/assignmentToVoidZero2.js ===
exports.j = 1;
>exports.j = 1 : 1
>exports.j : number
>exports.j : 1
>exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero2")
>j : number
>j : 1
>1 : 1
exports.k = void 0;
@@ -76,11 +76,11 @@ c.p + c.q
=== tests/cases/conformance/salsa/importer.js ===
import { j, k } from './assignmentToVoidZero2'
>j : number
>j : 1
>k : any
j + k
>j + k : any
>j : number
>j : 1
>k : any
@@ -5,8 +5,8 @@ const x = 0;
exports.y = 1;
>exports.y = 1 : 1
>exports.y : number
>exports.y : 1
>exports : typeof import("/a")
>y : number
>y : 1
>1 : 1
@@ -1,15 +1,15 @@
=== /a.js ===
exports.x = 0;
>exports.x = 0 : 0
>exports.x : number
>exports.x : 0
>exports : typeof import("/a")
>x : number
>x : 0
>0 : 0
exports.x;
>exports.x : number
>exports.x : 0
>exports : typeof import("/a")
>x : number
>x : 0
// Works nested
{
@@ -17,7 +17,7 @@ export {
//// [index.d.ts]
declare module "versions.static" {
var _default: {
const _default: {
"@a/b": string;
"@a/c": string;
};
@@ -10,17 +10,17 @@ module.exports = m.default;
>module.exports : typeof m.default
>module : { exports: typeof m.default; }
>exports : typeof m.default
>m.default : { (): void; memberName: string; }
>m.default : { (): void; memberName: "thing"; }
>m : typeof m
>default : { (): void; memberName: string; }
>default : { (): void; memberName: "thing"; }
module.exports.memberName = "thing";
>module.exports.memberName = "thing" : "thing"
>module.exports.memberName : string
>module.exports.memberName : "thing"
>module.exports : typeof m.default
>module : { exports: typeof m.default; }
>exports : typeof m.default
>memberName : string
>memberName : "thing"
>"thing" : "thing"
=== tests/cases/conformance/jsdoc/declarations/exporter.js ===
@@ -117,7 +117,7 @@ exports.default = func;
//// [index1.d.ts]
declare var _default: 12;
declare const _default: 12;
export default _default;
//// [index2.d.ts]
export default function foo(): typeof foo;
@@ -137,7 +137,7 @@ declare class Bar extends Fab {
import Fab from "./index3";
//// [index5.d.ts]
type _default = string | number;
declare var _default: 12;
declare const _default: 12;
export default _default;
//// [index6.d.ts]
declare function func(): void;
@@ -22,4 +22,4 @@ module.exports.additional = 20;
//// [index.d.ts]
export const member: number;
export const additional: number;
export const additional: 20;
@@ -12,19 +12,19 @@ class Foo {
}
module.exports = new Foo();
>module.exports = new Foo() : { member: number; additional: number; }
>module.exports : { member: number; additional: number; }
>module : { exports: { member: number; additional: number; }; }
>exports : { member: number; additional: number; }
>module.exports = new Foo() : { member: number; additional: 20; }
>module.exports : { member: number; additional: 20; }
>module : { exports: { member: number; additional: 20; }; }
>exports : { member: number; additional: 20; }
>new Foo() : Foo
>Foo : typeof Foo
module.exports.additional = 20;
>module.exports.additional = 20 : 20
>module.exports.additional : number
>module.exports : { member: number; additional: number; }
>module : { exports: { member: number; additional: number; }; }
>exports : { member: number; additional: number; }
>additional : number
>module.exports.additional : 20
>module.exports : { member: number; additional: 20; }
>module : { exports: { member: number; additional: 20; }; }
>exports : { member: number; additional: 20; }
>additional : 20
>20 : 20
@@ -14,7 +14,7 @@ export var dummy = 1
//// [mod1.d.ts]
/** @typedef {number} Dotted.Name */
export var dummy: number;
export const dummy: number;
export namespace Dotted {
type Name = number;
}
@@ -0,0 +1,15 @@
//// [file.js]
const customSymbol = Symbol("custom");
// This is a common pattern in Nodes built-in modules:
module.exports = {
customSymbol,
};
exports.customSymbol2 = Symbol("custom");
//// [file.d.ts]
export const customSymbol2: unique symbol;
export const customSymbol: unique symbol;
@@ -0,0 +1,22 @@
=== tests/cases/compiler/file.js ===
const customSymbol = Symbol("custom");
>customSymbol : Symbol(customSymbol, Decl(file.js, 0, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
// This is a common pattern in Nodes built-in modules:
module.exports = {
>module.exports : Symbol(module.exports, Decl(file.js, 0, 0))
>module : Symbol(module, Decl(file.js, 0, 38))
>exports : Symbol(module.exports, Decl(file.js, 0, 0))
customSymbol,
>customSymbol : Symbol(customSymbol, Decl(file.js, 3, 18))
};
exports.customSymbol2 = Symbol("custom");
>exports.customSymbol2 : Symbol(customSymbol2, Decl(file.js, 5, 2))
>exports : Symbol(customSymbol2, Decl(file.js, 5, 2))
>customSymbol2 : Symbol(customSymbol2, Decl(file.js, 5, 2))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
@@ -0,0 +1,29 @@
=== tests/cases/compiler/file.js ===
const customSymbol = Symbol("custom");
>customSymbol : unique symbol
>Symbol("custom") : unique symbol
>Symbol : SymbolConstructor
>"custom" : "custom"
// This is a common pattern in Nodes built-in modules:
module.exports = {
>module.exports = { customSymbol,} : typeof module.exports
>module.exports : typeof module.exports
>module : { exports: typeof module.exports; }
>exports : typeof module.exports
>{ customSymbol,} : { customSymbol: symbol; }
customSymbol,
>customSymbol : symbol
};
exports.customSymbol2 = Symbol("custom");
>exports.customSymbol2 = Symbol("custom") : unique symbol
>exports.customSymbol2 : unique symbol
>exports : typeof import("tests/cases/compiler/file")
>customSymbol2 : unique symbol
>Symbol("custom") : unique symbol
>Symbol : SymbolConstructor
>"custom" : "custom"
@@ -1,11 +1,11 @@
=== /x.js ===
module.exports.x = 1;
>module.exports.x = 1 : 1
>module.exports.x : number
>module.exports.x : 1
>module.exports : typeof import("/y")
>module : { exports: typeof import("/y"); }
>exports : typeof import("/y")
>x : number
>x : 1
>1 : 1
module.exports = require("./y.js");
@@ -21,9 +21,9 @@ var a = 10;
=== tests/cases/compiler/node_modules/c.js ===
exports.a = 10;
>exports.a = 10 : 10
>exports.a : number
>exports.a : 10
>exports : typeof import("tests/cases/compiler/node_modules/c")
>a : number
>a : 10
>10 : 10
c = 10;
@@ -5,19 +5,19 @@ const webpack = function (){
>function (){} : { (): void; WebpackOptionsDefaulter: number; }
}
exports = module.exports = webpack;
>exports = module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: number; }
>exports : { (): void; WebpackOptionsDefaulter: number; version: number; }
>module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: number; }
>module.exports : { (): void; WebpackOptionsDefaulter: number; version: number; }
>module : { exports: { (): void; WebpackOptionsDefaulter: number; version: number; }; }
>exports : { (): void; WebpackOptionsDefaulter: number; version: number; }
>exports = module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>module.exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>module : { exports: { (): void; WebpackOptionsDefaulter: number; version: 1001; }; }
>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>webpack : { (): void; WebpackOptionsDefaulter: number; }
exports.version = 1001;
>exports.version = 1001 : 1001
>exports.version : number
>exports : { (): void; WebpackOptionsDefaulter: number; version: number; }
>version : number
>exports.version : 1001
>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; }
>version : 1001
>1001 : 1001
webpack.WebpackOptionsDefaulter = 1111;
@@ -7,16 +7,16 @@
exports.bigOak = 1
>exports.bigOak = 1 : 1
>exports.bigOak : number
>exports.bigOak : 1
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>bigOak : number
>bigOak : 1
>1 : 1
exports.everywhere = 2
>exports.everywhere = 2 : 2
>exports.everywhere : number
>exports.everywhere : 2
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>everywhere : number
>everywhere : 2
>2 : 2
module.exports = exports
@@ -1,9 +1,9 @@
=== tests/cases/conformance/salsa/bug28014.js ===
exports.version = 1
>exports.version = 1 : 1
>exports.version : number
>exports.version : 1
>exports : typeof alias
>version : number
>version : 1
>1 : 1
function alias() { }
@@ -18,6 +18,6 @@ module.exports = alias
=== tests/cases/conformance/salsa/importer.js ===
import('./bug28014')
>import('./bug28014') : Promise<{ (): void; version: number; }>
>import('./bug28014') : Promise<{ (): void; version: 1; }>
>'./bug28014' : "./bug28014"
@@ -1,18 +1,18 @@
=== tests/cases/conformance/salsa/use.js ===
var npmlog = require('./npmlog')
>npmlog : { on(s: string): void; x: number; y: number; }
>require('./npmlog') : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>require('./npmlog') : { on(s: string): void; x: number; y: 2; }
>require : any
>'./npmlog' : "./npmlog"
npmlog.x
>npmlog.x : number
>npmlog : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>x : number
npmlog.on
>npmlog.on : (s: string) => void
>npmlog : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>on : (s: string) => void
=== tests/cases/conformance/salsa/npmlog.js ===
@@ -25,55 +25,55 @@ class EE {
>s : string
}
var npmlog = module.exports = new EE()
>npmlog : { on(s: string): void; x: number; y: number; }
>module.exports = new EE() : { on(s: string): void; x: number; y: number; }
>module.exports : { on(s: string): void; x: number; y: number; }
>module : { exports: { on(s: string): void; x: number; y: number; }; }
>exports : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>module.exports = new EE() : { on(s: string): void; x: number; y: 2; }
>module.exports : { on(s: string): void; x: number; y: 2; }
>module : { exports: { on(s: string): void; x: number; y: 2; }; }
>exports : { on(s: string): void; x: number; y: 2; }
>new EE() : EE
>EE : typeof EE
npmlog.on('hi') // both references should see EE.on
>npmlog.on('hi') : void
>npmlog.on : (s: string) => void
>npmlog : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>on : (s: string) => void
>'hi' : "hi"
module.exports.on('hi') // here too
>module.exports.on('hi') : void
>module.exports.on : (s: string) => void
>module.exports : { on(s: string): void; x: number; y: number; }
>module : { exports: { on(s: string): void; x: number; y: number; }; }
>exports : { on(s: string): void; x: number; y: number; }
>module.exports : { on(s: string): void; x: number; y: 2; }
>module : { exports: { on(s: string): void; x: number; y: 2; }; }
>exports : { on(s: string): void; x: number; y: 2; }
>on : (s: string) => void
>'hi' : "hi"
npmlog.x = 1
>npmlog.x = 1 : 1
>npmlog.x : number
>npmlog : { on(s: string): void; x: number; y: number; }
>npmlog : { on(s: string): void; x: number; y: 2; }
>x : number
>1 : 1
module.exports.y = 2
>module.exports.y = 2 : 2
>module.exports.y : number
>module.exports : { on(s: string): void; x: number; y: number; }
>module : { exports: { on(s: string): void; x: number; y: number; }; }
>exports : { on(s: string): void; x: number; y: number; }
>y : number
>module.exports.y : 2
>module.exports : { on(s: string): void; x: number; y: 2; }
>module : { exports: { on(s: string): void; x: number; y: 2; }; }
>exports : { on(s: string): void; x: number; y: 2; }
>y : 2
>2 : 2
npmlog.y
>npmlog.y : number
>npmlog : { on(s: string): void; x: number; y: number; }
>y : number
>npmlog.y : 2
>npmlog : { on(s: string): void; x: number; y: 2; }
>y : 2
module.exports.x
>module.exports.x : number
>module.exports : { on(s: string): void; x: number; y: number; }
>module : { exports: { on(s: string): void; x: number; y: number; }; }
>exports : { on(s: string): void; x: number; y: number; }
>module.exports : { on(s: string): void; x: number; y: 2; }
>module : { exports: { on(s: string): void; x: number; y: 2; }; }
>exports : { on(s: string): void; x: number; y: 2; }
>x : number
@@ -32,7 +32,7 @@ var result = apply.toFixed();
//// [moduleExportAliasDuplicateAlias.d.ts]
export var apply: string | number | typeof a | undefined;
export const apply: typeof a | "ok" | 1 | undefined;
export { a as apply };
declare function a(): void;
//// [test.d.ts]
@@ -15,16 +15,16 @@ const result = apply.toFixed()
=== tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias.js ===
exports.apply = undefined;
>exports.apply = undefined : undefined
>exports.apply : string | number | (() => void) | undefined
>exports.apply : (() => void) | "ok" | 1 | undefined
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string | number | (() => void) | undefined
>apply : (() => void) | "ok" | 1 | undefined
>undefined : undefined
exports.apply = undefined;
>exports.apply = undefined : undefined
>exports.apply : string | number | (() => void) | undefined
>exports.apply : (() => void) | "ok" | 1 | undefined
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string | number | (() => void) | undefined
>apply : (() => void) | "ok" | 1 | undefined
>undefined : undefined
function a() { }
@@ -32,9 +32,9 @@ function a() { }
exports.apply = a;
>exports.apply = a : () => void
>exports.apply : string | number | (() => void) | undefined
>exports.apply : (() => void) | "ok" | 1 | undefined
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string | number | (() => void) | undefined
>apply : (() => void) | "ok" | 1 | undefined
>a : () => void
exports.apply()
@@ -45,24 +45,24 @@ exports.apply()
exports.apply = 'ok'
>exports.apply = 'ok' : "ok"
>exports.apply : string | number | (() => void) | undefined
>exports.apply : (() => void) | "ok" | 1 | undefined
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string | number | (() => void) | undefined
>apply : (() => void) | "ok" | 1 | undefined
>'ok' : "ok"
var OK = exports.apply.toUpperCase()
>OK : string
>exports.apply.toUpperCase() : string
>exports.apply.toUpperCase : () => string
>exports.apply : string
>exports.apply : "ok"
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string
>apply : "ok"
>toUpperCase : () => string
exports.apply = 1
>exports.apply = 1 : 1
>exports.apply : string | number | (() => void) | undefined
>exports.apply : (() => void) | "ok" | 1 | undefined
>exports : typeof import("tests/cases/conformance/salsa/moduleExportAliasDuplicateAlias")
>apply : string | number | (() => void) | undefined
>apply : (() => void) | "ok" | 1 | undefined
>1 : 1
@@ -1,7 +1,7 @@
tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'string | number'.
Property 'toFixed' does not exist on type 'string'.
tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'string | number'.
Property 'toFixed' does not exist on type 'string'.
tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
Property 'toFixed' does not exist on type '"string"'.
tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
Property 'toFixed' does not exist on type '"string"'.
==== tests/cases/conformance/salsa/a.js (2 errors) ====
@@ -10,12 +10,12 @@ tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does
mod1.justExport.toFixed()
mod1.bothBefore.toFixed() // error, 'toFixed' not on 'string | number'
~~~~~~~
!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'.
!!! error TS2339: Property 'toFixed' does not exist on type 'string'.
!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
!!! error TS2339: Property 'toFixed' does not exist on type '"string"'.
mod1.bothAfter.toFixed() // error, 'toFixed' not on 'string | number'
~~~~~~~
!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'.
!!! error TS2339: Property 'toFixed' does not exist on type 'string'.
!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
!!! error TS2339: Property 'toFixed' does not exist on type '"string"'.
mod1.justProperty.length
==== tests/cases/conformance/salsa/requires.d.ts (0 errors) ====
@@ -1,8 +1,8 @@
=== tests/cases/conformance/salsa/a.js ===
/// <reference path='./requires.d.ts' />
var mod1 = require('./mod1')
>mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>require('./mod1') : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>require('./mod1') : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>require : (name: string) => any
>'./mod1' : "./mod1"
@@ -10,31 +10,31 @@ mod1.justExport.toFixed()
>mod1.justExport.toFixed() : string
>mod1.justExport.toFixed : (fractionDigits?: number) => string
>mod1.justExport : number
>mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>justExport : number
>toFixed : (fractionDigits?: number) => string
mod1.bothBefore.toFixed() // error, 'toFixed' not on 'string | number'
>mod1.bothBefore.toFixed() : any
>mod1.bothBefore.toFixed : any
>mod1.bothBefore : string | number
>mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>bothBefore : string | number
>mod1.bothBefore : number | "string"
>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>bothBefore : number | "string"
>toFixed : any
mod1.bothAfter.toFixed() // error, 'toFixed' not on 'string | number'
>mod1.bothAfter.toFixed() : any
>mod1.bothAfter.toFixed : any
>mod1.bothAfter : string | number
>mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>bothAfter : string | number
>mod1.bothAfter : number | "string"
>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>bothAfter : number | "string"
>toFixed : any
mod1.justProperty.length
>mod1.justProperty.length : number
>mod1.justProperty : string
>mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>justProperty : string
>mod1.justProperty : "string"
>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>justProperty : "string"
>length : number
=== tests/cases/conformance/salsa/requires.d.ts ===
@@ -50,18 +50,18 @@ declare function require(name: string): any;
/// <reference path='./requires.d.ts' />
module.exports.bothBefore = 'string'
>module.exports.bothBefore = 'string' : "string"
>module.exports.bothBefore : string | number
>module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module : { exports: { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; }
>exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>bothBefore : string | number
>module.exports.bothBefore : number | "string"
>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>module : { exports: { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; }
>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>bothBefore : number | "string"
>'string' : "string"
module.exports = {
>module.exports = { justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module : { exports: { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; }
>exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module.exports = { justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>module : { exports: { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; }
>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>{ justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: number; bothAfter: number; }
justExport: 1,
@@ -78,19 +78,19 @@ module.exports = {
}
module.exports.bothAfter = 'string'
>module.exports.bothAfter = 'string' : "string"
>module.exports.bothAfter : string | number
>module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module : { exports: { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; }
>exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>bothAfter : string | number
>module.exports.bothAfter : number | "string"
>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>module : { exports: { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; }
>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>bothAfter : number | "string"
>'string' : "string"
module.exports.justProperty = 'string'
>module.exports.justProperty = 'string' : "string"
>module.exports.justProperty : string
>module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>module : { exports: { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; }
>exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }
>justProperty : string
>module.exports.justProperty : "string"
>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>module : { exports: { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; }
>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }
>justProperty : "string"
>'string' : "string"
@@ -1,7 +1,7 @@
tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'string | number'.
Property 'toFixed' does not exist on type 'string'.
tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'string | number'.
Property 'toFixed' does not exist on type 'string'.
tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
Property 'toFixed' does not exist on type '"string"'.
tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
Property 'toFixed' does not exist on type '"string"'.
tests/cases/conformance/salsa/mod1.js(2,1): error TS2323: Cannot redeclare exported variable 'bothBefore'.
tests/cases/conformance/salsa/mod1.js(4,1): error TS2323: Cannot redeclare exported variable 'bothBefore'.
tests/cases/conformance/salsa/mod1.js(5,1): error TS2323: Cannot redeclare exported variable 'bothAfter'.
@@ -14,12 +14,12 @@ tests/cases/conformance/salsa/mod1.js(10,1): error TS2323: Cannot redeclare expo
mod1.justExport.toFixed()
mod1.bothBefore.toFixed() // error
~~~~~~~
!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'.
!!! error TS2339: Property 'toFixed' does not exist on type 'string'.
!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
!!! error TS2339: Property 'toFixed' does not exist on type '"string"'.
mod1.bothAfter.toFixed()
~~~~~~~
!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'.
!!! error TS2339: Property 'toFixed' does not exist on type 'string'.
!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'.
!!! error TS2339: Property 'toFixed' does not exist on type '"string"'.
mod1.justProperty.length
==== tests/cases/conformance/salsa/requires.d.ts (0 errors) ====
@@ -17,24 +17,24 @@ mod1.justExport.toFixed()
mod1.bothBefore.toFixed() // error
>mod1.bothBefore.toFixed() : any
>mod1.bothBefore.toFixed : any
>mod1.bothBefore : string | number
>mod1.bothBefore : number | "string"
>mod1 : typeof mod1
>bothBefore : string | number
>bothBefore : number | "string"
>toFixed : any
mod1.bothAfter.toFixed()
>mod1.bothAfter.toFixed() : any
>mod1.bothAfter.toFixed : any
>mod1.bothAfter : string | number
>mod1.bothAfter : number | "string"
>mod1 : typeof mod1
>bothAfter : string | number
>bothAfter : number | "string"
>toFixed : any
mod1.justProperty.length
>mod1.justProperty.length : number
>mod1.justProperty : string
>mod1.justProperty : "string"
>mod1 : typeof mod1
>justProperty : string
>justProperty : "string"
>length : number
=== tests/cases/conformance/salsa/requires.d.ts ===
@@ -50,11 +50,11 @@ declare function require(name: string): any;
/// <reference path='./requires.d.ts' />
module.exports.bothBefore = 'string'
>module.exports.bothBefore = 'string' : "string"
>module.exports.bothBefore : string | number
>module.exports.bothBefore : number | "string"
>module.exports : typeof A
>module : { exports: typeof A; }
>exports : typeof A
>bothBefore : string | number
>bothBefore : number | "string"
>'string' : "string"
A.justExport = 4
@@ -66,16 +66,16 @@ A.justExport = 4
A.bothBefore = 2
>A.bothBefore = 2 : 2
>A.bothBefore : string | number
>A.bothBefore : number | "string"
>A : typeof A
>bothBefore : string | number
>bothBefore : number | "string"
>2 : 2
A.bothAfter = 3
>A.bothAfter = 3 : 3
>A.bothAfter : string | number
>A.bothAfter : number | "string"
>A : typeof A
>bothAfter : string | number
>bothAfter : number | "string"
>3 : 3
module.exports = A
@@ -97,19 +97,19 @@ function A() {
}
module.exports.bothAfter = 'string'
>module.exports.bothAfter = 'string' : "string"
>module.exports.bothAfter : string | number
>module.exports.bothAfter : number | "string"
>module.exports : typeof A
>module : { exports: typeof A; }
>exports : typeof A
>bothAfter : string | number
>bothAfter : number | "string"
>'string' : "string"
module.exports.justProperty = 'string'
>module.exports.justProperty = 'string' : "string"
>module.exports.justProperty : string
>module.exports.justProperty : "string"
>module.exports : typeof A
>module : { exports: typeof A; }
>exports : typeof A
>justProperty : string
>justProperty : "string"
>'string' : "string"
@@ -1,12 +1,12 @@
=== /src/index.ts ===
import { x } from "../node_modules/foo";
>x : number
>x : 0
=== /node_modules/foo/index.js ===
exports.x = 0;
>exports.x = 0 : 0
>exports.x : number
>exports.x : 0
>exports : typeof import("/node_modules/foo/index")
>x : number
>x : 0
>0 : 0
@@ -1,9 +1,9 @@
=== tests/cases/conformance/node/allowJs/foo.cjs ===
exports.foo = "foo"
>exports.foo = "foo" : "foo"
>exports.foo : string
>exports.foo : "foo"
>exports : typeof import("tests/cases/conformance/node/allowJs/foo")
>foo : string
>foo : "foo"
>"foo" : "foo"
=== tests/cases/conformance/node/allowJs/bar.ts ===
@@ -11,7 +11,7 @@ import foo from "./foo.cjs"
>foo : typeof foo
foo.foo;
>foo.foo : string
>foo.foo : "foo"
>foo : typeof foo
>foo : string
>foo : "foo"
@@ -1,9 +1,9 @@
=== tests/cases/conformance/node/allowJs/foo.cjs ===
exports.foo = "foo"
>exports.foo = "foo" : "foo"
>exports.foo : string
>exports.foo : "foo"
>exports : typeof import("tests/cases/conformance/node/allowJs/foo")
>foo : string
>foo : "foo"
>"foo" : "foo"
=== tests/cases/conformance/node/allowJs/bar.ts ===
@@ -11,7 +11,7 @@ import foo from "./foo.cjs"
>foo : typeof foo
foo.foo;
>foo.foo : string
>foo.foo : "foo"
>foo : typeof foo
>foo : string
>foo : "foo"
@@ -1,7 +1,7 @@
=== tests/cases/conformance/jsdoc/use.js ===
var mod = require('./mod1.js');
>mod : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: number; } | { Quack: number; Bar: typeof mod.Bar; Quid: number; }
>require('./mod1.js') : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: number; } | { Quack: number; Bar: typeof mod.Bar; Quid: number; }
>mod : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: 2; } | { Quack: number; Bar: typeof mod.Bar; Quid: 2; }
>require('./mod1.js') : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: 2; } | { Quack: number; Bar: typeof mod.Bar; Quid: 2; }
>require : any
>'./mod1.js' : "./mod1.js"
@@ -17,7 +17,7 @@ var bbb = new mod.Baz();
>bbb : any
>new mod.Baz() : any
>mod.Baz : any
>mod : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: number; } | { Quack: number; Bar: typeof mod.Bar; Quid: number; }
>mod : { Baz: typeof Baz; Bar: typeof mod.Bar; Quid: 2; } | { Quack: number; Bar: typeof mod.Bar; Quid: 2; }
>Baz : any
=== tests/cases/conformance/jsdoc/mod1.js ===
@@ -31,16 +31,16 @@ class Foo { } // should error
exports.Bar = class { }
>exports.Bar = class { } : typeof Bar
>exports.Bar : typeof Bar
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>Bar : typeof Bar
>class { } : typeof Bar
/** @typedef {number} Baz */
module.exports = {
>module.exports = { Baz: class { }} : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module : { exports: { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }; }
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module.exports = { Baz: class { }} : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>module : { exports: { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }; }
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>{ Baz: class { }} : { Baz: typeof Baz; }
Baz: class { }
@@ -58,17 +58,17 @@ var Qux = 2;
/** @typedef {number} Quid */
exports.Quid = 2;
>exports.Quid = 2 : 2
>exports.Quid : number
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>Quid : number
>exports.Quid : 2
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>Quid : 2
>2 : 2
/** @typedef {number} Quack */
module.exports = {
>module.exports = { Quack: 2} : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module : { exports: { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }; }
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }
>module.exports = { Quack: 2} : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>module : { exports: { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }; }
>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }
>{ Quack: 2} : { Quack: number; }
Quack: 2
@@ -0,0 +1,15 @@
// @declaration: true
// @emitDeclarationOnly: true
// @allowJs: true
// @checkJs: true
// @module: commonjs
// @target: es6
// @filename: file.js
const customSymbol = Symbol("custom");
// This is a common pattern in Nodes built-in modules:
module.exports = {
customSymbol,
};
exports.customSymbol2 = Symbol("custom");
@@ -16,13 +16,13 @@ goTo.file('/b.js')
const markers = test.markers();
verify.getInlayHints([
{
text: ': number',
text: ': 1',
position: markers[0].position,
kind: ts.InlayHintKind.Type,
whitespaceBefore: true
},
{
text: ': number',
text: ': 1',
position: markers[1].position,
kind: ts.InlayHintKind.Type,
whitespaceBefore: true