diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bd6c5d02cbe..c628d8ab1dd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22321,8 +22321,17 @@ namespace ts { leftType; case SyntaxKind.EqualsToken: const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; - checkAssignmentDeclaration(declKind, right); + checkAssignmentDeclaration(declKind, rightType); if (isAssignmentDeclaration(declKind)) { + if (!(rightType.flags & TypeFlags.Object) || + declKind !== AssignmentDeclarationKind.ModuleExports && + declKind !== AssignmentDeclarationKind.Prototype && + !isEmptyObjectType(rightType) && + !isFunctionObjectType(rightType as ObjectType) && + !(getObjectFlags(rightType) & ObjectFlags.Class)) { + // don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete + checkAssignmentOperator(rightType); + } return leftType; } else { @@ -22339,9 +22348,8 @@ namespace ts { return Debug.fail(); } - function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, right: Expression) { + function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) { if (kind === AssignmentDeclarationKind.ModuleExports) { - const rightType = checkExpression(right, checkMode); for (const prop of getPropertiesOfObjectType(rightType)) { const propType = getTypeOfSymbol(prop); if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { diff --git a/tests/baselines/reference/typeTagModuleExports.errors.txt b/tests/baselines/reference/typeTagModuleExports.errors.txt new file mode 100644 index 00000000000..1ef675996ab --- /dev/null +++ b/tests/baselines/reference/typeTagModuleExports.errors.txt @@ -0,0 +1,9 @@ +tests/cases/conformance/jsdoc/bug27327.js(2,1): error TS2322: Type '0' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ==== + /** @type {string} */ + module.exports = 0; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '0' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeTagModuleExports.symbols b/tests/baselines/reference/typeTagModuleExports.symbols new file mode 100644 index 00000000000..a625e8dd77b --- /dev/null +++ b/tests/baselines/reference/typeTagModuleExports.symbols @@ -0,0 +1,7 @@ +=== tests/cases/conformance/jsdoc/bug27327.js === +/** @type {string} */ +module.exports = 0; +>module.exports : Symbol("tests/cases/conformance/jsdoc/bug27327", Decl(bug27327.js, 0, 0)) +>module : Symbol(export=, Decl(bug27327.js, 0, 0)) +>exports : Symbol(export=, Decl(bug27327.js, 0, 0)) + diff --git a/tests/baselines/reference/typeTagModuleExports.types b/tests/baselines/reference/typeTagModuleExports.types new file mode 100644 index 00000000000..0e5c5282894 --- /dev/null +++ b/tests/baselines/reference/typeTagModuleExports.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/bug27327.js === +/** @type {string} */ +module.exports = 0; +>module.exports = 0 : string +>module.exports : string +>module : { "tests/cases/conformance/jsdoc/bug27327": string; } +>exports : string +>0 : 0 + diff --git a/tests/baselines/reference/typeTagPrototypeAssignment.errors.txt b/tests/baselines/reference/typeTagPrototypeAssignment.errors.txt new file mode 100644 index 00000000000..f80916b793e --- /dev/null +++ b/tests/baselines/reference/typeTagPrototypeAssignment.errors.txt @@ -0,0 +1,11 @@ +tests/cases/conformance/jsdoc/bug27327.js(4,1): error TS2322: Type '12' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ==== + function C() { + } + /** @type {string} */ + C.prototype = 12 + ~~~~~~~~~~~ +!!! error TS2322: Type '12' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeTagPrototypeAssignment.symbols b/tests/baselines/reference/typeTagPrototypeAssignment.symbols new file mode 100644 index 00000000000..0ef0cb4c20d --- /dev/null +++ b/tests/baselines/reference/typeTagPrototypeAssignment.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/jsdoc/bug27327.js === +function C() { +>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1)) +} +/** @type {string} */ +C.prototype = 12 +>C.prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1)) +>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1)) +>prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1)) + diff --git a/tests/baselines/reference/typeTagPrototypeAssignment.types b/tests/baselines/reference/typeTagPrototypeAssignment.types new file mode 100644 index 00000000000..7f54d7b0c03 --- /dev/null +++ b/tests/baselines/reference/typeTagPrototypeAssignment.types @@ -0,0 +1,12 @@ +=== tests/cases/conformance/jsdoc/bug27327.js === +function C() { +>C : typeof C +} +/** @type {string} */ +C.prototype = 12 +>C.prototype = 12 : 12 +>C.prototype : string +>C : typeof C +>prototype : string +>12 : 12 + diff --git a/tests/cases/conformance/jsdoc/typeTagModuleExports.ts b/tests/cases/conformance/jsdoc/typeTagModuleExports.ts new file mode 100644 index 00000000000..79a3e31ca11 --- /dev/null +++ b/tests/cases/conformance/jsdoc/typeTagModuleExports.ts @@ -0,0 +1,6 @@ +// @Filename: bug27327.js +// @noEmit: true +// @allowJs: true +// @checkJs: true +/** @type {string} */ +module.exports = 0; diff --git a/tests/cases/conformance/jsdoc/typeTagPrototypeAssignment.ts b/tests/cases/conformance/jsdoc/typeTagPrototypeAssignment.ts new file mode 100644 index 00000000000..c8018bce1bf --- /dev/null +++ b/tests/cases/conformance/jsdoc/typeTagPrototypeAssignment.ts @@ -0,0 +1,8 @@ +// @Filename: bug27327.js +// @noEmit: true +// @allowJs: true +// @checkJs: true +function C() { +} +/** @type {string} */ +C.prototype = 12