diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 292bfe51340db..3fba2894002cc 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2112,7 +2112,7 @@ namespace ts { // Nothing to do break; default: - Debug.fail("Unknown special property assignment kind"); + Debug.fail("Unknown binary expression special property assignment kind"); } return checkStrictModeBinaryExpression(node); case SyntaxKind.CatchClause: @@ -2188,6 +2188,19 @@ namespace ts { return bindFunctionExpression(node); case SyntaxKind.CallExpression: + const assignmentKind = getAssignmentDeclarationKind(node as CallExpression); + switch (assignmentKind) { + case AssignmentDeclarationKind.ObjectDefinePropertyValue: + return bindObjectDefinePropertyAssignment(node as BindableObjectDefinePropertyCall); + case AssignmentDeclarationKind.ObjectDefinePropertyExports: + return bindObjectDefinePropertyExport(node as BindableObjectDefinePropertyCall); + case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: + return bindObjectDefinePrototypeProperty(node as BindableObjectDefinePropertyCall); + case AssignmentDeclarationKind.None: + break; // Nothing to do + default: + return Debug.fail("Unknown call expression assignment declaration kind"); + } if (isInJSFile(node)) { bindCallExpression(node); } @@ -2351,6 +2364,22 @@ namespace ts { return true; } + function bindObjectDefinePropertyExport(node: BindableObjectDefinePropertyCall) { + if (!setCommonJsModuleIndicator(node)) { + return; + } + const symbol = forEachIdentifierInEntityName(node.arguments[0], /*parent*/ undefined, (id, symbol) => { + if (symbol) { + addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment); + } + return symbol; + }); + if (symbol) { + const flags = SymbolFlags.Property | SymbolFlags.ExportValue; + declareSymbol(symbol.exports!, symbol, node, flags, SymbolFlags.None); + } + } + function bindExportsPropertyAssignment(node: BinaryExpression) { // When we create a property via 'exports.foo = bar', the 'exports.foo' property access // expression is the declaration @@ -2458,6 +2487,11 @@ namespace ts { bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false); } + function bindObjectDefinePrototypeProperty(node: BindableObjectDefinePropertyCall) { + const namespaceSymbol = lookupSymbolForPropertyAccess((node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression); + bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ true); + } + /** * For `x.prototype.y = z`, declare a member `y` on `x` if `x` is a function or class, or not declared. * Note that jsdoc preceding an ExpressionStatement like `x.prototype.y;` is also treated as a declaration. @@ -2476,6 +2510,12 @@ namespace ts { bindPropertyAssignment(constructorFunction, lhs, /*isPrototypeProperty*/ true); } + function bindObjectDefinePropertyAssignment(node: BindableObjectDefinePropertyCall) { + let namespaceSymbol = lookupSymbolForPropertyAccess(node.arguments[0]); + const isToplevel = node.parent.parent.kind === SyntaxKind.SourceFile; + namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, node.arguments[0], isToplevel, /*isPrototypeProperty*/ false); + bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ false); + } function bindSpecialPropertyAssignment(node: BinaryExpression) { const lhs = node.left as PropertyAccessEntityNameExpression; @@ -2507,16 +2547,12 @@ namespace ts { bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false); } - function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) { - let namespaceSymbol = lookupSymbolForPropertyAccess(name); - const isToplevel = isBinaryExpression(propertyAccess.parent) - ? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile - : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; + function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: EntityNameExpression, isToplevel: boolean, isPrototypeProperty: boolean) { if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) { // make symbols or add declarations for intermediate containers const flags = SymbolFlags.Module | SymbolFlags.Assignment; const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment; - namespaceSymbol = forEachIdentifierInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => { + namespaceSymbol = forEachIdentifierInEntityName(entityName, namespaceSymbol, (id, symbol, parent) => { if (symbol) { addDeclarationToSymbol(symbol, id, flags); return symbol; @@ -2528,6 +2564,10 @@ namespace ts { } }); } + return namespaceSymbol; + } + + function bindPotentiallyNewExpandoMemberToNamespace(declaration: PropertyAccessEntityNameExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) { if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) { return; } @@ -2537,10 +2577,19 @@ namespace ts { (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) : (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable())); - const isMethod = isFunctionLikeDeclaration(getAssignedExpandoInitializer(propertyAccess)!); + const isMethod = isFunctionLikeDeclaration(getAssignedExpandoInitializer(declaration)!); const includes = isMethod ? SymbolFlags.Method : SymbolFlags.Property; const excludes = isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes; - declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment); + declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment); + } + + function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) { + let namespaceSymbol = lookupSymbolForPropertyAccess(name); + const isToplevel = isBinaryExpression(propertyAccess.parent) + ? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile + : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; + namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty); + bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty); } /** diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eca967ce8282d..ea5e27c2c9e5a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4881,7 +4881,7 @@ namespace ts { let jsdocType: Type | undefined; let types: Type[] | undefined; for (const declaration of symbol.declarations) { - const expression = isBinaryExpression(declaration) ? declaration : + const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration : isPropertyAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration : undefined; if (!expression) { @@ -4897,9 +4897,11 @@ namespace ts { definedInMethod = true; } } - jsdocType = getJSDocTypeFromAssignmentDeclaration(jsdocType, expression, symbol, declaration); + if (!isCallExpression(expression)) { + jsdocType = getJSDocTypeFromAssignmentDeclaration(jsdocType, expression, symbol, declaration); + } if (!jsdocType) { - (types || (types = [])).push(isBinaryExpression(expression) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); + (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); } } let type = jsdocType; @@ -4960,7 +4962,32 @@ namespace ts { } /** If we don't have an explicit JSDoc type, get the type from the initializer. */ - function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression, kind: AssignmentDeclarationKind) { + function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { + if (isCallExpression(expression)) { + if (resolvedSymbol) { + return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments + } + const objectLitType = checkExpressionCached((expression as BindableObjectDefinePropertyCall).arguments[2]); + const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); + if (valueType) { + return valueType; + } + const getFunc = getTypeOfPropertyOfType(objectLitType, "get" as __String); + if (getFunc) { + const getSig = getSingleCallSignature(getFunc); + if (getSig) { + return getReturnTypeOfSignature(getSig); + } + } + const setFunc = getTypeOfPropertyOfType(objectLitType, "set" as __String); + if (setFunc) { + const setSig = getSingleCallSignature(setFunc); + if (setSig) { + return getTypeOfFirstParameterOfSignature(setSig); + } + } + return anyType; + } const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : getWidenedLiteralType(checkExpressionCached(expression.right)); if (type.flags & TypeFlags.Object && kind === AssignmentDeclarationKind.ModuleExports && @@ -5212,7 +5239,7 @@ namespace ts { } let type: Type | undefined; if (isInJSFile(declaration) && - (isBinaryExpression(declaration) || isPropertyAccessExpression(declaration) && isBinaryExpression(declaration.parent))) { + (isCallExpression(declaration) || isBinaryExpression(declaration) || isPropertyAccessExpression(declaration) && isBinaryExpression(declaration.parent))) { type = getWidenedTypeFromAssignmentDeclaration(symbol); } else if (isJSDocPropertyLikeTag(declaration) @@ -16179,6 +16206,31 @@ namespace ts { getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype) { return (container.parent.parent.parent.left as PropertyAccessExpression).expression; } + // Object.defineProperty(x, "method", { value: function() { } }); + // Object.defineProperty(x, "method", { set: (x: () => void) => void }); + // Object.defineProperty(x, "method", { get: () => function() { }) }); + else if (container.kind === SyntaxKind.FunctionExpression && + isPropertyAssignment(container.parent) && + isIdentifier(container.parent.name) && + (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" || container.parent.name.escapedText === "set") && + isObjectLiteralExpression(container.parent.parent) && + isCallExpression(container.parent.parent.parent) && + container.parent.parent.parent.arguments[2] === container.parent.parent && + getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { + return (container.parent.parent.parent.arguments[0] as PropertyAccessExpression).expression; + } + // Object.defineProperty(x, "method", { value() { } }); + // Object.defineProperty(x, "method", { set(x: () => void) {} }); + // Object.defineProperty(x, "method", { get() { return () => {} } }); + else if (isMethodDeclaration(container) && + isIdentifier(container.name) && + (container.name.escapedText === "value" || container.name.escapedText === "get" || container.name.escapedText === "set") && + isObjectLiteralExpression(container.parent) && + isCallExpression(container.parent.parent) && + container.parent.parent.arguments[2] === container.parent && + getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { + return (container.parent.parent.arguments[0] as PropertyAccessExpression).expression; + } } function getTypeForThisExpressionFromJSDoc(node: Node) { @@ -16741,6 +16793,10 @@ namespace ts { } const thisType = checkThisExpression(thisAccess.expression); return thisType && getTypeOfPropertyOfContextualType(thisType, thisAccess.name.escapedText) || false; + case AssignmentDeclarationKind.ObjectDefinePropertyValue: + case AssignmentDeclarationKind.ObjectDefinePropertyExports: + case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: + return Debug.fail("Does not apply"); default: return Debug.assertNever(kind); } @@ -21132,18 +21188,52 @@ namespace ts { return true; } + function isReadonlyAssignmentDeclaration(d: Declaration) { + if (!isCallExpression(d)) { + return false; + } + if (!isBindableObjectDefinePropertyCall(d)) { + return false; + } + const objectLitType = checkExpressionCached(d.arguments[2]); + const valueType = getTypeOfPropertyOfType(objectLitType, "value" as __String); + if (valueType) { + const writableProp = getPropertyOfType(objectLitType, "writable" as __String); + const writableType = writableProp && getTypeOfSymbol(writableProp); + if (!writableType || writableType === falseType || writableType === regularFalseType) { + return true; + } + // We include this definition whereupon we walk back and check the type at the declaration because + // The usual definition of `Object.defineProperty` will _not_ cause literal types to be preserved in the + // argument types, should the type be contextualized by the call itself. + if (writableProp && writableProp.valueDeclaration && isPropertyAssignment(writableProp.valueDeclaration)) { + const initializer = writableProp.valueDeclaration.initializer; + const rawOriginalType = checkExpression(initializer); + if (rawOriginalType === falseType || rawOriginalType === regularFalseType) { + return true; + } + } + return false; + } + const setProp = getPropertyOfType(objectLitType, "set" as __String); + return !setProp; + } + function isReadonlySymbol(symbol: Symbol): boolean { // The following symbols are considered read-only: // Properties with a 'readonly' modifier // Variables declared with 'const' // Get accessors without matching set accessors // Enum members + // Object.defineProperty assignments with writable false or no setter // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation) return !!(getCheckFlags(symbol) & CheckFlags.Readonly || symbol.flags & SymbolFlags.Property && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly || symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const || symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || - symbol.flags & SymbolFlags.EnumMember); + symbol.flags & SymbolFlags.EnumMember || + some(symbol.declarations, isReadonlyAssignmentDeclaration) + ); } function isReferenceToReadonlyEntity(expr: Expression, symbol: Symbol): boolean { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 610cc4e61c7a7..fe31a30a30f08 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -790,7 +790,7 @@ namespace ts { export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - export type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern; export interface Declaration extends Node { _declarationBrand: any; @@ -1774,6 +1774,9 @@ namespace ts { arguments: NodeArray; } + /** @internal */ + export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: EntityNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } }; + // see: https://tc39.github.io/ecma262/#prod-SuperCall export interface SuperCall extends CallExpression { expression: SuperExpression; @@ -4347,6 +4350,15 @@ namespace ts { Property, // F.prototype = { ... } Prototype, + // Object.defineProperty(x, 'name', { value: any, writable?: boolean (false by default) }); + // Object.defineProperty(x, 'name', { get: Function, set: Function }); + // Object.defineProperty(x, 'name', { get: Function }); + // Object.defineProperty(x, 'name', { set: Function }); + ObjectDefinePropertyValue, + // Object.defineProperty(exports || module.exports, 'name', ...); + ObjectDefinePropertyExports, + // Object.defineProperty(Foo.prototype, 'name', ...); + ObjectDefinePrototypeProperty, } /** @deprecated Use FileExtensionInfo instead. */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index acaabdab9c7be..6310d299b4283 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -765,12 +765,13 @@ namespace ts { return info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : undefined; } - export function getTextOfPropertyName(name: PropertyName): __String { + export function getTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral): __String { switch (name.kind) { case SyntaxKind.Identifier: return name.escapedText; case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: return escapeLeadingUnderscores(name.text); case SyntaxKind.ComputedPropertyName: return isStringOrNumericLiteralLike(name.expression) ? escapeLeadingUnderscores(name.expression.text) : undefined!; // TODO: GH#18217 Almost all uses of this assume the result to be defined! @@ -1770,7 +1771,7 @@ namespace ts { } export function isAssignmentDeclaration(decl: Declaration) { - return isBinaryExpression(decl) || isPropertyAccessExpression(decl) || isIdentifier(decl); + return isBinaryExpression(decl) || isPropertyAccessExpression(decl) || isIdentifier(decl) || isCallExpression(decl); } /** Get the initializer, taking into account defaulted Javascript initializers */ @@ -1905,12 +1906,35 @@ namespace ts { /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder - export function getAssignmentDeclarationKind(expr: BinaryExpression): AssignmentDeclarationKind { + export function getAssignmentDeclarationKind(expr: BinaryExpression | CallExpression): AssignmentDeclarationKind { const special = getAssignmentDeclarationKindWorker(expr); return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special : AssignmentDeclarationKind.None; } - function getAssignmentDeclarationKindWorker(expr: BinaryExpression): AssignmentDeclarationKind { + export function isBindableObjectDefinePropertyCall(expr: CallExpression): expr is BindableObjectDefinePropertyCall { + return length(expr.arguments) === 3 && + isPropertyAccessExpression(expr.expression) && + isIdentifier(expr.expression.expression) && + idText(expr.expression.expression) === "Object" && + idText(expr.expression.name) === "defineProperty" && + isStringOrNumericLiteralLike(expr.arguments[1]) && + isEntityNameExpression(expr.arguments[0]); + } + + function getAssignmentDeclarationKindWorker(expr: BinaryExpression | CallExpression): AssignmentDeclarationKind { + if (isCallExpression(expr)) { + if (!isBindableObjectDefinePropertyCall(expr)) { + return AssignmentDeclarationKind.None; + } + const entityName = expr.arguments[0]; + if (isExportsIdentifier(entityName) || isModuleExportsPropertyAccessExpression(entityName)) { + return AssignmentDeclarationKind.ObjectDefinePropertyExports; + } + if (isPropertyAccessExpression(entityName) && entityName.name.escapedText === "prototype" && isEntityNameExpression(entityName.expression)) { + return AssignmentDeclarationKind.ObjectDefinePrototypeProperty; + } + return AssignmentDeclarationKind.ObjectDefinePropertyValue; + } if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isPropertyAccessExpression(expr.left)) { return AssignmentDeclarationKind.None; @@ -1927,7 +1951,7 @@ namespace ts { if (lhs.expression.kind === SyntaxKind.ThisKeyword) { return AssignmentDeclarationKind.ThisProperty; } - else if (isIdentifier(lhs.expression) && lhs.expression.escapedText === "module" && lhs.name.escapedText === "exports") { + else if (isModuleExportsPropertyAccessExpression(lhs)) { // module.exports = expr return AssignmentDeclarationKind.ModuleExports; } @@ -4977,14 +5001,19 @@ namespace ts { } break; } + case SyntaxKind.CallExpression: case SyntaxKind.BinaryExpression: { - const expr = declaration as BinaryExpression; + const expr = declaration as BinaryExpression | CallExpression; switch (getAssignmentDeclarationKind(expr)) { case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.ThisProperty: case AssignmentDeclarationKind.Property: case AssignmentDeclarationKind.PrototypeProperty: - return (expr.left as PropertyAccessExpression).name; + return ((expr as BinaryExpression).left as PropertyAccessExpression).name; + case AssignmentDeclarationKind.ObjectDefinePropertyValue: + case AssignmentDeclarationKind.ObjectDefinePropertyExports: + case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: + return (expr as BindableObjectDefinePropertyCall).arguments[1]; default: return undefined; } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 03d2aec13c54d..760d6e7103103 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -281,6 +281,9 @@ namespace ts.NavigationBar { case AssignmentDeclarationKind.ThisProperty: case AssignmentDeclarationKind.Property: case AssignmentDeclarationKind.None: + case AssignmentDeclarationKind.ObjectDefinePropertyValue: + case AssignmentDeclarationKind.ObjectDefinePropertyExports: + case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: break; default: Debug.assertNever(special); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 427c31e53845e..e53f568c0f417 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -368,6 +368,9 @@ namespace ts { const kind = getAssignmentDeclarationKind(node as BinaryExpression); const { right } = node as BinaryExpression; switch (kind) { + case AssignmentDeclarationKind.ObjectDefinePropertyValue: + case AssignmentDeclarationKind.ObjectDefinePropertyExports: + case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: case AssignmentDeclarationKind.None: return ScriptElementKind.unknown; case AssignmentDeclarationKind.ExportsProperty: diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 00b93acbba514..a7e8d3e569056 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -526,7 +526,7 @@ declare namespace ts { } type EntityName = Identifier | QualifiedName; type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern; interface Declaration extends Node { _declarationBrand: any; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 34b5ade8841a4..0c2485d1a2566 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -526,7 +526,7 @@ declare namespace ts { } type EntityName = Identifier | QualifiedName; type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName; - type DeclarationName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | BindingPattern; + type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern; interface Declaration extends Node { _declarationBrand: any; } diff --git a/tests/baselines/reference/checkExportsObjectAssignProperty.errors.txt b/tests/baselines/reference/checkExportsObjectAssignProperty.errors.txt new file mode 100644 index 0000000000000..266c2180a685f --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignProperty.errors.txt @@ -0,0 +1,110 @@ +tests/cases/conformance/jsdoc/validator.ts(17,4): error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(18,4): error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(19,1): error TS2322: Type '"no"' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/validator.ts(20,1): error TS2322: Type '"no"' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/validator.ts(21,1): error TS2322: Type '0' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/validator.ts(37,4): error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(38,4): error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(39,1): error TS2322: Type '0' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/validator.ts(40,1): error TS2322: Type '"no"' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/validator.ts(41,1): error TS2322: Type '0' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/validator.ts (10 errors) ==== + import "./"; + + import m1 = require("./mod1"); + + m1.thing; + m1.readonlyProp; + m1.rwAccessors; + m1.readonlyAccessor; + m1.setonlyAccessor; + + // allowed assignments + m1.thing = 10; + m1.rwAccessors = 11; + m1.setonlyAccessor = "yes"; + + // disallowed assignments + m1.readonlyProp = "name"; + ~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. + m1.readonlyAccessor = 12; + ~~~~~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. + m1.thing = "no"; + ~~~~~~~~ +!!! error TS2322: Type '"no"' is not assignable to type 'number'. + m1.rwAccessors = "no"; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '"no"' is not assignable to type 'number'. + m1.setonlyAccessor = 0; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '0' is not assignable to type 'string'. + + import m2 = require("./mod2"); + + m2.thing; + m2.readonlyProp; + m2.rwAccessors; + m2.readonlyAccessor; + m2.setonlyAccessor; + + // allowed assignments + m2.thing = "ok"; + m2.rwAccessors = 11; + m2.setonlyAccessor = "yes"; + + // disallowed assignments + m2.readonlyProp = "name"; + ~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. + m2.readonlyAccessor = 12; + ~~~~~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. + m2.thing = 0; + ~~~~~~~~ +!!! error TS2322: Type '0' is not assignable to type 'string'. + m2.rwAccessors = "no"; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '"no"' is not assignable to type 'number'. + m2.setonlyAccessor = 0; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '0' is not assignable to type 'string'. + +==== tests/cases/conformance/jsdoc/mod1.js (0 errors) ==== + Object.defineProperty(exports, "thing", { value: 42, writable: true }); + Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false }); + Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); + Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } }); + Object.defineProperty(exports, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } + }); + +==== tests/cases/conformance/jsdoc/mod2.js (0 errors) ==== + Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }); + Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }); + Object.defineProperty(module.exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); + Object.defineProperty(module.exports, "readonlyAccessor", { get() { return 21.75 } }); + Object.defineProperty(module.exports, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } + }); + +==== tests/cases/conformance/jsdoc/index.js (0 errors) ==== + /** + * @type {number} + */ + const q = require("./mod1").thing; + + /** + * @type {string} + */ + const u = require("./mod2").thing; + \ No newline at end of file diff --git a/tests/baselines/reference/checkExportsObjectAssignProperty.symbols b/tests/baselines/reference/checkExportsObjectAssignProperty.symbols new file mode 100644 index 0000000000000..d33e2de1e209a --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignProperty.symbols @@ -0,0 +1,276 @@ +=== tests/cases/conformance/jsdoc/validator.ts === +import "./"; + +import m1 = require("./mod1"); +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) + +m1.thing; +>m1.thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) + +m1.readonlyProp; +>m1.readonlyProp : Symbol(m1["readonlyProp"], Decl(mod1.js, 0, 71)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>readonlyProp : Symbol(m1["readonlyProp"], Decl(mod1.js, 0, 71)) + +m1.rwAccessors; +>m1.rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) + +m1.readonlyAccessor; +>m1.readonlyAccessor : Symbol(m1["readonlyAccessor"], Decl(mod1.js, 2, 97)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>readonlyAccessor : Symbol(m1["readonlyAccessor"], Decl(mod1.js, 2, 97)) + +m1.setonlyAccessor; +>m1.setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) + +// allowed assignments +m1.thing = 10; +>m1.thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) + +m1.rwAccessors = 11; +>m1.rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) + +m1.setonlyAccessor = "yes"; +>m1.setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) + +// disallowed assignments +m1.readonlyProp = "name"; +>m1.readonlyProp : Symbol(m1["readonlyProp"], Decl(mod1.js, 0, 71)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>readonlyProp : Symbol(m1["readonlyProp"], Decl(mod1.js, 0, 71)) + +m1.readonlyAccessor = 12; +>m1.readonlyAccessor : Symbol(m1["readonlyAccessor"], Decl(mod1.js, 2, 97)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>readonlyAccessor : Symbol(m1["readonlyAccessor"], Decl(mod1.js, 2, 97)) + +m1.thing = "no"; +>m1.thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>thing : Symbol(m1["thing"], Decl(mod1.js, 0, 0)) + +m1.rwAccessors = "no"; +>m1.rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>rwAccessors : Symbol(m1["rwAccessors"], Decl(mod1.js, 1, 84)) + +m1.setonlyAccessor = 0; +>m1.setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) +>m1 : Symbol(m1, Decl(validator.ts, 0, 12)) +>setonlyAccessor : Symbol(m1["setonlyAccessor"], Decl(mod1.js, 3, 79)) + +import m2 = require("./mod2"); +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) + +m2.thing; +>m2.thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) + +m2.readonlyProp; +>m2.readonlyProp : Symbol(m2["readonlyProp"], Decl(mod2.js, 0, 81)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>readonlyProp : Symbol(m2["readonlyProp"], Decl(mod2.js, 0, 81)) + +m2.rwAccessors; +>m2.rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) + +m2.readonlyAccessor; +>m2.readonlyAccessor : Symbol(m2["readonlyAccessor"], Decl(mod2.js, 2, 104)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>readonlyAccessor : Symbol(m2["readonlyAccessor"], Decl(mod2.js, 2, 104)) + +m2.setonlyAccessor; +>m2.setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) + +// allowed assignments +m2.thing = "ok"; +>m2.thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) + +m2.rwAccessors = 11; +>m2.rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) + +m2.setonlyAccessor = "yes"; +>m2.setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) + +// disallowed assignments +m2.readonlyProp = "name"; +>m2.readonlyProp : Symbol(m2["readonlyProp"], Decl(mod2.js, 0, 81)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>readonlyProp : Symbol(m2["readonlyProp"], Decl(mod2.js, 0, 81)) + +m2.readonlyAccessor = 12; +>m2.readonlyAccessor : Symbol(m2["readonlyAccessor"], Decl(mod2.js, 2, 104)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>readonlyAccessor : Symbol(m2["readonlyAccessor"], Decl(mod2.js, 2, 104)) + +m2.thing = 0; +>m2.thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>thing : Symbol(m2["thing"], Decl(mod2.js, 0, 0)) + +m2.rwAccessors = "no"; +>m2.rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>rwAccessors : Symbol(m2["rwAccessors"], Decl(mod2.js, 1, 91)) + +m2.setonlyAccessor = 0; +>m2.setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) +>m2 : Symbol(m2, Decl(validator.ts, 20, 23)) +>setonlyAccessor : Symbol(m2["setonlyAccessor"], Decl(mod2.js, 3, 86)) + +=== tests/cases/conformance/jsdoc/mod1.js === +Object.defineProperty(exports, "thing", { value: 42, writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>value : Symbol(value, Decl(mod1.js, 0, 41)) +>writable : Symbol(writable, Decl(mod1.js, 0, 52)) + +Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>value : Symbol(value, Decl(mod1.js, 1, 48)) +>writable : Symbol(writable, Decl(mod1.js, 1, 64)) + +Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>get : Symbol(get, Decl(mod1.js, 2, 47)) +>set : Symbol(set, Decl(mod1.js, 2, 71)) +>_ : Symbol(_, Decl(mod1.js, 2, 76)) + +Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>get : Symbol(get, Decl(mod1.js, 3, 52)) + +Object.defineProperty(exports, "setonlyAccessor", { +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) + + /** @param {string} str */ + set(str) { +>set : Symbol(set, Decl(mod1.js, 4, 51)) +>str : Symbol(str, Decl(mod1.js, 6, 8)) + + this.rwAccessors = Number(str) +>rwAccessors : Symbol(rwAccessors, Decl(mod1.js, 6, 14)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>str : Symbol(str, Decl(mod1.js, 6, 8)) + } +}); + +=== tests/cases/conformance/jsdoc/mod2.js === +Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>module : Symbol(module, Decl(mod2.js, 0, 22)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>value : Symbol(value, Decl(mod2.js, 0, 48)) +>writable : Symbol(writable, Decl(mod2.js, 0, 62)) + +Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>module : Symbol(module, Decl(mod2.js, 0, 22)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>value : Symbol(value, Decl(mod2.js, 1, 55)) +>writable : Symbol(writable, Decl(mod2.js, 1, 71)) + +Object.defineProperty(module.exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>module : Symbol(module, Decl(mod2.js, 0, 22)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>get : Symbol(get, Decl(mod2.js, 2, 54)) +>set : Symbol(set, Decl(mod2.js, 2, 78)) +>_ : Symbol(_, Decl(mod2.js, 2, 83)) + +Object.defineProperty(module.exports, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>module : Symbol(module, Decl(mod2.js, 0, 22)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>get : Symbol(get, Decl(mod2.js, 3, 59)) + +Object.defineProperty(module.exports, "setonlyAccessor", { +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>module : Symbol(module, Decl(mod2.js, 0, 22)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) + + /** @param {string} str */ + set(str) { +>set : Symbol(set, Decl(mod2.js, 4, 58)) +>str : Symbol(str, Decl(mod2.js, 6, 8)) + + this.rwAccessors = Number(str) +>rwAccessors : Symbol(rwAccessors, Decl(mod2.js, 6, 14)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>str : Symbol(str, Decl(mod2.js, 6, 8)) + } +}); + +=== tests/cases/conformance/jsdoc/index.js === +/** + * @type {number} + */ +const q = require("./mod1").thing; +>q : Symbol(q, Decl(index.js, 3, 5)) +>require("./mod1").thing : Symbol("thing", Decl(mod1.js, 0, 0)) +>require : Symbol(require) +>"./mod1" : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>thing : Symbol("thing", Decl(mod1.js, 0, 0)) + +/** + * @type {string} + */ +const u = require("./mod2").thing; +>u : Symbol(u, Decl(index.js, 8, 5)) +>require("./mod2").thing : Symbol("thing", Decl(mod2.js, 0, 0)) +>require : Symbol(require) +>"./mod2" : Symbol("tests/cases/conformance/jsdoc/mod2", Decl(mod2.js, 0, 0)) +>thing : Symbol("thing", Decl(mod2.js, 0, 0)) + diff --git a/tests/baselines/reference/checkExportsObjectAssignProperty.types b/tests/baselines/reference/checkExportsObjectAssignProperty.types new file mode 100644 index 0000000000000..847ac720d75c1 --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignProperty.types @@ -0,0 +1,360 @@ +=== tests/cases/conformance/jsdoc/validator.ts === +import "./"; + +import m1 = require("./mod1"); +>m1 : typeof m1 + +m1.thing; +>m1.thing : number +>m1 : typeof m1 +>thing : number + +m1.readonlyProp; +>m1.readonlyProp : string +>m1 : typeof m1 +>readonlyProp : string + +m1.rwAccessors; +>m1.rwAccessors : number +>m1 : typeof m1 +>rwAccessors : number + +m1.readonlyAccessor; +>m1.readonlyAccessor : number +>m1 : typeof m1 +>readonlyAccessor : number + +m1.setonlyAccessor; +>m1.setonlyAccessor : string +>m1 : typeof m1 +>setonlyAccessor : string + +// allowed assignments +m1.thing = 10; +>m1.thing = 10 : 10 +>m1.thing : number +>m1 : typeof m1 +>thing : number +>10 : 10 + +m1.rwAccessors = 11; +>m1.rwAccessors = 11 : 11 +>m1.rwAccessors : number +>m1 : typeof m1 +>rwAccessors : number +>11 : 11 + +m1.setonlyAccessor = "yes"; +>m1.setonlyAccessor = "yes" : "yes" +>m1.setonlyAccessor : string +>m1 : typeof m1 +>setonlyAccessor : string +>"yes" : "yes" + +// disallowed assignments +m1.readonlyProp = "name"; +>m1.readonlyProp = "name" : "name" +>m1.readonlyProp : any +>m1 : typeof m1 +>readonlyProp : any +>"name" : "name" + +m1.readonlyAccessor = 12; +>m1.readonlyAccessor = 12 : 12 +>m1.readonlyAccessor : any +>m1 : typeof m1 +>readonlyAccessor : any +>12 : 12 + +m1.thing = "no"; +>m1.thing = "no" : "no" +>m1.thing : number +>m1 : typeof m1 +>thing : number +>"no" : "no" + +m1.rwAccessors = "no"; +>m1.rwAccessors = "no" : "no" +>m1.rwAccessors : number +>m1 : typeof m1 +>rwAccessors : number +>"no" : "no" + +m1.setonlyAccessor = 0; +>m1.setonlyAccessor = 0 : 0 +>m1.setonlyAccessor : string +>m1 : typeof m1 +>setonlyAccessor : string +>0 : 0 + +import m2 = require("./mod2"); +>m2 : typeof m2 + +m2.thing; +>m2.thing : string +>m2 : typeof m2 +>thing : string + +m2.readonlyProp; +>m2.readonlyProp : string +>m2 : typeof m2 +>readonlyProp : string + +m2.rwAccessors; +>m2.rwAccessors : number +>m2 : typeof m2 +>rwAccessors : number + +m2.readonlyAccessor; +>m2.readonlyAccessor : number +>m2 : typeof m2 +>readonlyAccessor : number + +m2.setonlyAccessor; +>m2.setonlyAccessor : string +>m2 : typeof m2 +>setonlyAccessor : string + +// allowed assignments +m2.thing = "ok"; +>m2.thing = "ok" : "ok" +>m2.thing : string +>m2 : typeof m2 +>thing : string +>"ok" : "ok" + +m2.rwAccessors = 11; +>m2.rwAccessors = 11 : 11 +>m2.rwAccessors : number +>m2 : typeof m2 +>rwAccessors : number +>11 : 11 + +m2.setonlyAccessor = "yes"; +>m2.setonlyAccessor = "yes" : "yes" +>m2.setonlyAccessor : string +>m2 : typeof m2 +>setonlyAccessor : string +>"yes" : "yes" + +// disallowed assignments +m2.readonlyProp = "name"; +>m2.readonlyProp = "name" : "name" +>m2.readonlyProp : any +>m2 : typeof m2 +>readonlyProp : any +>"name" : "name" + +m2.readonlyAccessor = 12; +>m2.readonlyAccessor = 12 : 12 +>m2.readonlyAccessor : any +>m2 : typeof m2 +>readonlyAccessor : any +>12 : 12 + +m2.thing = 0; +>m2.thing = 0 : 0 +>m2.thing : string +>m2 : typeof m2 +>thing : string +>0 : 0 + +m2.rwAccessors = "no"; +>m2.rwAccessors = "no" : "no" +>m2.rwAccessors : number +>m2 : typeof m2 +>rwAccessors : number +>"no" : "no" + +m2.setonlyAccessor = 0; +>m2.setonlyAccessor = 0 : 0 +>m2.setonlyAccessor : string +>m2 : typeof m2 +>setonlyAccessor : string +>0 : 0 + +=== tests/cases/conformance/jsdoc/mod1.js === +Object.defineProperty(exports, "thing", { value: 42, writable: true }); +>Object.defineProperty(exports, "thing", { value: 42, writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"thing" : "thing" +>{ value: 42, writable: true } : { value: number; writable: true; } +>value : number +>42 : 42 +>writable : true +>true : true + +Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"readonlyProp" : "readonlyProp" +>{ value: "Smith", writable: false } : { value: string; writable: false; } +>value : string +>"Smith" : "Smith" +>writable : false +>false : false + +Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"rwAccessors" : "rwAccessors" +>{ get() { return 98122 }, set(_) { /*ignore*/ } } : { get(): number; set(_: any): void; } +>get : () => number +>98122 : 98122 +>set : (_: any) => void +>_ : any + +Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"readonlyAccessor" : "readonlyAccessor" +>{ get() { return 21.75 } } : { get(): number; } +>get : () => number +>21.75 : 21.75 + +Object.defineProperty(exports, "setonlyAccessor", { +>Object.defineProperty(exports, "setonlyAccessor", { /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }}) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"setonlyAccessor" : "setonlyAccessor" +>{ /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }} : { set(str: string): void; } + + /** @param {string} str */ + set(str) { +>set : (str: string) => void +>str : string + + this.rwAccessors = Number(str) +>this.rwAccessors = Number(str) : number +>this.rwAccessors : any +>this : any +>rwAccessors : any +>Number(str) : number +>Number : NumberConstructor +>str : string + } +}); + +=== tests/cases/conformance/jsdoc/mod2.js === +Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }); +>Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module.exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>module : { "tests/cases/conformance/jsdoc/mod2": typeof import("tests/cases/conformance/jsdoc/mod2"); } +>exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>"thing" : "thing" +>{ value: "yes", writable: true } : { value: string; writable: true; } +>value : string +>"yes" : "yes" +>writable : true +>true : true + +Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module.exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>module : { "tests/cases/conformance/jsdoc/mod2": typeof import("tests/cases/conformance/jsdoc/mod2"); } +>exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>"readonlyProp" : "readonlyProp" +>{ value: "Smith", writable: false } : { value: string; writable: false; } +>value : string +>"Smith" : "Smith" +>writable : false +>false : false + +Object.defineProperty(module.exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty(module.exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module.exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>module : { "tests/cases/conformance/jsdoc/mod2": typeof import("tests/cases/conformance/jsdoc/mod2"); } +>exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>"rwAccessors" : "rwAccessors" +>{ get() { return 98122 }, set(_) { /*ignore*/ } } : { get(): number; set(_: any): void; } +>get : () => number +>98122 : 98122 +>set : (_: any) => void +>_ : any + +Object.defineProperty(module.exports, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty(module.exports, "readonlyAccessor", { get() { return 21.75 } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module.exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>module : { "tests/cases/conformance/jsdoc/mod2": typeof import("tests/cases/conformance/jsdoc/mod2"); } +>exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>"readonlyAccessor" : "readonlyAccessor" +>{ get() { return 21.75 } } : { get(): number; } +>get : () => number +>21.75 : 21.75 + +Object.defineProperty(module.exports, "setonlyAccessor", { +>Object.defineProperty(module.exports, "setonlyAccessor", { /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }}) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module.exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>module : { "tests/cases/conformance/jsdoc/mod2": typeof import("tests/cases/conformance/jsdoc/mod2"); } +>exports : typeof import("tests/cases/conformance/jsdoc/mod2") +>"setonlyAccessor" : "setonlyAccessor" +>{ /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }} : { set(str: string): void; } + + /** @param {string} str */ + set(str) { +>set : (str: string) => void +>str : string + + this.rwAccessors = Number(str) +>this.rwAccessors = Number(str) : number +>this.rwAccessors : any +>this : any +>rwAccessors : any +>Number(str) : number +>Number : NumberConstructor +>str : string + } +}); + +=== tests/cases/conformance/jsdoc/index.js === +/** + * @type {number} + */ +const q = require("./mod1").thing; +>q : number +>require("./mod1").thing : number +>require("./mod1") : typeof import("tests/cases/conformance/jsdoc/mod1") +>require : any +>"./mod1" : "./mod1" +>thing : number + +/** + * @type {string} + */ +const u = require("./mod2").thing; +>u : string +>require("./mod2").thing : string +>require("./mod2") : typeof import("tests/cases/conformance/jsdoc/mod2") +>require : any +>"./mod2" : "./mod2" +>thing : string + diff --git a/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.errors.txt b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.errors.txt new file mode 100644 index 0000000000000..c2621a71b9915 --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.errors.txt @@ -0,0 +1,66 @@ +tests/cases/conformance/jsdoc/validator.ts(19,4): error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(20,4): error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validator.ts(21,1): error TS2322: Type '"no"' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/validator.ts(22,1): error TS2322: Type '"no"' is not assignable to type 'number'. +tests/cases/conformance/jsdoc/validator.ts(23,1): error TS2322: Type '0' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/validator.ts (5 errors) ==== + import "./"; + + import Person = require("./mod1"); + + const m1 = new Person("Name") + + m1.thing; + m1.readonlyProp; + m1.rwAccessors; + m1.readonlyAccessor; + m1.setonlyAccessor; + + // allowed assignments + m1.thing = 10; + m1.rwAccessors = 11; + m1.setonlyAccessor = "yes"; + + // disallowed assignments + m1.readonlyProp = "name"; + ~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyProp' because it is a constant or a read-only property. + m1.readonlyAccessor = 12; + ~~~~~~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'readonlyAccessor' because it is a constant or a read-only property. + m1.thing = "no"; + ~~~~~~~~ +!!! error TS2322: Type '"no"' is not assignable to type 'number'. + m1.rwAccessors = "no"; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '"no"' is not assignable to type 'number'. + m1.setonlyAccessor = 0; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '0' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/mod1.js (0 errors) ==== + /** + * @constructor + * @param {string} name + */ + function Person(name) { + this.name = name; + } + Person.prototype.describe = function () { + return "Person called " + this.name; + }; + Object.defineProperty(Person.prototype, "thing", { value: 42, writable: true }); + Object.defineProperty(Person.prototype, "readonlyProp", { value: "Smith", writable: false }); + Object.defineProperty(Person.prototype, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); + Object.defineProperty(Person.prototype, "readonlyAccessor", { get() { return 21.75 } }); + Object.defineProperty(Person.prototype, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } + }); + module.exports = Person; + \ No newline at end of file diff --git a/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.symbols b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.symbols new file mode 100644 index 0000000000000..9f04a3600cce9 --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.symbols @@ -0,0 +1,172 @@ +=== tests/cases/conformance/jsdoc/validator.ts === +import "./"; + +import Person = require("./mod1"); +>Person : Symbol(Person, Decl(validator.ts, 0, 12)) + +const m1 = new Person("Name") +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>Person : Symbol(Person, Decl(validator.ts, 0, 12)) + +m1.thing; +>m1.thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) + +m1.readonlyProp; +>m1.readonlyProp : Symbol(Person["readonlyProp"], Decl(mod1.js, 10, 80)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>readonlyProp : Symbol(Person["readonlyProp"], Decl(mod1.js, 10, 80)) + +m1.rwAccessors; +>m1.rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) + +m1.readonlyAccessor; +>m1.readonlyAccessor : Symbol(Person["readonlyAccessor"], Decl(mod1.js, 12, 106)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>readonlyAccessor : Symbol(Person["readonlyAccessor"], Decl(mod1.js, 12, 106)) + +m1.setonlyAccessor; +>m1.setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) + +// allowed assignments +m1.thing = 10; +>m1.thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) + +m1.rwAccessors = 11; +>m1.rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) + +m1.setonlyAccessor = "yes"; +>m1.setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) + +// disallowed assignments +m1.readonlyProp = "name"; +>m1.readonlyProp : Symbol(Person["readonlyProp"], Decl(mod1.js, 10, 80)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>readonlyProp : Symbol(Person["readonlyProp"], Decl(mod1.js, 10, 80)) + +m1.readonlyAccessor = 12; +>m1.readonlyAccessor : Symbol(Person["readonlyAccessor"], Decl(mod1.js, 12, 106)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>readonlyAccessor : Symbol(Person["readonlyAccessor"], Decl(mod1.js, 12, 106)) + +m1.thing = "no"; +>m1.thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>thing : Symbol(Person["thing"], Decl(mod1.js, 9, 2)) + +m1.rwAccessors = "no"; +>m1.rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) + +m1.setonlyAccessor = 0; +>m1.setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) +>m1 : Symbol(m1, Decl(validator.ts, 4, 5)) +>setonlyAccessor : Symbol(Person["setonlyAccessor"], Decl(mod1.js, 13, 88)) + + +=== tests/cases/conformance/jsdoc/mod1.js === +/** + * @constructor + * @param {string} name + */ +function Person(name) { +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>name : Symbol(name, Decl(mod1.js, 4, 16)) + + this.name = name; +>this.name : Symbol(Person.name, Decl(mod1.js, 4, 23)) +>this : Symbol(Person, Decl(mod1.js, 0, 0)) +>name : Symbol(Person.name, Decl(mod1.js, 4, 23)) +>name : Symbol(name, Decl(mod1.js, 4, 16)) +} +Person.prototype.describe = function () { +>Person.prototype : Symbol(Person.describe, Decl(mod1.js, 6, 1)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>describe : Symbol(Person.describe, Decl(mod1.js, 6, 1)) + + return "Person called " + this.name; +>this.name : Symbol(Person.name, Decl(mod1.js, 4, 23)) +>this : Symbol(Person, Decl(mod1.js, 0, 0)) +>name : Symbol(Person.name, Decl(mod1.js, 4, 23)) + +}; +Object.defineProperty(Person.prototype, "thing", { value: 42, writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Person.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(mod1.js, 10, 50)) +>writable : Symbol(writable, Decl(mod1.js, 10, 61)) + +Object.defineProperty(Person.prototype, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Person.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(mod1.js, 11, 57)) +>writable : Symbol(writable, Decl(mod1.js, 11, 73)) + +Object.defineProperty(Person.prototype, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Person.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>get : Symbol(get, Decl(mod1.js, 12, 56)) +>set : Symbol(set, Decl(mod1.js, 12, 80)) +>_ : Symbol(_, Decl(mod1.js, 12, 85)) + +Object.defineProperty(Person.prototype, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Person.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>get : Symbol(get, Decl(mod1.js, 13, 61)) + +Object.defineProperty(Person.prototype, "setonlyAccessor", { +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Person.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) + + /** @param {string} str */ + set(str) { +>set : Symbol(set, Decl(mod1.js, 14, 60)) +>str : Symbol(str, Decl(mod1.js, 16, 8)) + + this.rwAccessors = Number(str) +>this.rwAccessors : Symbol(Person["rwAccessors"], Decl(mod1.js, 11, 93)) +>this : Symbol(Person, Decl(mod1.js, 0, 0)) +>rwAccessors : Symbol(rwAccessors, Decl(mod1.js, 16, 14)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>str : Symbol(str, Decl(mod1.js, 16, 8)) + } +}); +module.exports = Person; +>module.exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>module : Symbol(export=, Decl(mod1.js, 19, 3)) +>exports : Symbol(export=, Decl(mod1.js, 19, 3)) +>Person : Symbol(Person, Decl(mod1.js, 0, 0)) + diff --git a/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.types b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.types new file mode 100644 index 0000000000000..662c578701f56 --- /dev/null +++ b/tests/baselines/reference/checkExportsObjectAssignPrototypeProperty.types @@ -0,0 +1,220 @@ +=== tests/cases/conformance/jsdoc/validator.ts === +import "./"; + +import Person = require("./mod1"); +>Person : typeof Person + +const m1 = new Person("Name") +>m1 : Person +>new Person("Name") : Person +>Person : typeof Person +>"Name" : "Name" + +m1.thing; +>m1.thing : number +>m1 : Person +>thing : number + +m1.readonlyProp; +>m1.readonlyProp : string +>m1 : Person +>readonlyProp : string + +m1.rwAccessors; +>m1.rwAccessors : number +>m1 : Person +>rwAccessors : number + +m1.readonlyAccessor; +>m1.readonlyAccessor : number +>m1 : Person +>readonlyAccessor : number + +m1.setonlyAccessor; +>m1.setonlyAccessor : string +>m1 : Person +>setonlyAccessor : string + +// allowed assignments +m1.thing = 10; +>m1.thing = 10 : 10 +>m1.thing : number +>m1 : Person +>thing : number +>10 : 10 + +m1.rwAccessors = 11; +>m1.rwAccessors = 11 : 11 +>m1.rwAccessors : number +>m1 : Person +>rwAccessors : number +>11 : 11 + +m1.setonlyAccessor = "yes"; +>m1.setonlyAccessor = "yes" : "yes" +>m1.setonlyAccessor : string +>m1 : Person +>setonlyAccessor : string +>"yes" : "yes" + +// disallowed assignments +m1.readonlyProp = "name"; +>m1.readonlyProp = "name" : "name" +>m1.readonlyProp : any +>m1 : Person +>readonlyProp : any +>"name" : "name" + +m1.readonlyAccessor = 12; +>m1.readonlyAccessor = 12 : 12 +>m1.readonlyAccessor : any +>m1 : Person +>readonlyAccessor : any +>12 : 12 + +m1.thing = "no"; +>m1.thing = "no" : "no" +>m1.thing : number +>m1 : Person +>thing : number +>"no" : "no" + +m1.rwAccessors = "no"; +>m1.rwAccessors = "no" : "no" +>m1.rwAccessors : number +>m1 : Person +>rwAccessors : number +>"no" : "no" + +m1.setonlyAccessor = 0; +>m1.setonlyAccessor = 0 : 0 +>m1.setonlyAccessor : string +>m1 : Person +>setonlyAccessor : string +>0 : 0 + + +=== tests/cases/conformance/jsdoc/mod1.js === +/** + * @constructor + * @param {string} name + */ +function Person(name) { +>Person : typeof Person +>name : string + + this.name = name; +>this.name = name : string +>this.name : string +>this : Person +>name : string +>name : string +} +Person.prototype.describe = function () { +>Person.prototype.describe = function () { return "Person called " + this.name;} : () => string +>Person.prototype.describe : any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>describe : any +>function () { return "Person called " + this.name;} : () => string + + return "Person called " + this.name; +>"Person called " + this.name : string +>"Person called " : "Person called " +>this.name : string +>this : Person +>name : string + +}; +Object.defineProperty(Person.prototype, "thing", { value: 42, writable: true }); +>Object.defineProperty(Person.prototype, "thing", { value: 42, writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>"thing" : "thing" +>{ value: 42, writable: true } : { value: number; writable: true; } +>value : number +>42 : 42 +>writable : true +>true : true + +Object.defineProperty(Person.prototype, "readonlyProp", { value: "Smith", writable: false }); +>Object.defineProperty(Person.prototype, "readonlyProp", { value: "Smith", writable: false }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>"readonlyProp" : "readonlyProp" +>{ value: "Smith", writable: false } : { value: string; writable: false; } +>value : string +>"Smith" : "Smith" +>writable : false +>false : false + +Object.defineProperty(Person.prototype, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty(Person.prototype, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>"rwAccessors" : "rwAccessors" +>{ get() { return 98122 }, set(_) { /*ignore*/ } } : { get(): number; set(_: any): void; } +>get : () => number +>98122 : 98122 +>set : (_: any) => void +>_ : any + +Object.defineProperty(Person.prototype, "readonlyAccessor", { get() { return 21.75 } }); +>Object.defineProperty(Person.prototype, "readonlyAccessor", { get() { return 21.75 } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>"readonlyAccessor" : "readonlyAccessor" +>{ get() { return 21.75 } } : { get(): number; } +>get : () => number +>21.75 : 21.75 + +Object.defineProperty(Person.prototype, "setonlyAccessor", { +>Object.defineProperty(Person.prototype, "setonlyAccessor", { /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }}) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Person.prototype : any +>Person : typeof Person +>prototype : any +>"setonlyAccessor" : "setonlyAccessor" +>{ /** @param {string} str */ set(str) { this.rwAccessors = Number(str) }} : { set(str: string): void; } + + /** @param {string} str */ + set(str) { +>set : (str: string) => void +>str : string + + this.rwAccessors = Number(str) +>this.rwAccessors = Number(str) : number +>this.rwAccessors : number +>this : Person +>rwAccessors : number +>Number(str) : number +>Number : NumberConstructor +>str : string + } +}); +module.exports = Person; +>module.exports = Person : typeof Person +>module.exports : typeof Person +>module : { "tests/cases/conformance/jsdoc/mod1": typeof Person; } +>exports : typeof Person +>Person : typeof Person + diff --git a/tests/baselines/reference/checkObjectDefineProperty.errors.txt b/tests/baselines/reference/checkObjectDefineProperty.errors.txt new file mode 100644 index 0000000000000..b587955ef2f81 --- /dev/null +++ b/tests/baselines/reference/checkObjectDefineProperty.errors.txt @@ -0,0 +1,79 @@ +tests/cases/conformance/jsdoc/validate.ts(14,3): error TS2540: Cannot assign to 'lastName' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validate.ts(15,3): error TS2540: Cannot assign to 'houseNumber' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/validate.ts(16,1): error TS2322: Type '12' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/validate.ts(17,3): error TS2540: Cannot assign to 'middleInit' because it is a constant or a read-only property. + + +==== tests/cases/conformance/jsdoc/validate.ts (4 errors) ==== + // Validate in TS as simple validations would usually be interpreted as more special assignments + import x = require("./"); + x.name; + x.middleInit; + x.lastName; + x.zip; + x.houseNumber; + x.zipStr; + + x.name = "Another"; + x.zip = 98123; + x.zipStr = "OK"; + + x.lastName = "should fail"; + ~~~~~~~~ +!!! error TS2540: Cannot assign to 'lastName' because it is a constant or a read-only property. + x.houseNumber = 12; // should also fail + ~~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'houseNumber' because it is a constant or a read-only property. + x.zipStr = 12; // should fail + ~~~~~~~~ +!!! error TS2322: Type '12' is not assignable to type 'string'. + x.middleInit = "R"; // should also fail + ~~~~~~~~~~ +!!! error TS2540: Cannot assign to 'middleInit' because it is a constant or a read-only property. + +==== tests/cases/conformance/jsdoc/index.js (0 errors) ==== + const x = {}; + Object.defineProperty(x, "name", { value: "Charles", writable: true }); + Object.defineProperty(x, "middleInit", { value: "H" }); + Object.defineProperty(x, "lastName", { value: "Smith", writable: false }); + Object.defineProperty(x, "zip", { get() { return 98122 }, set(_) { /*ignore*/ } }); + Object.defineProperty(x, "houseNumber", { get() { return 21.75 } }); + Object.defineProperty(x, "zipStr", { + /** @param {string} str */ + set(str) { + this.zip = Number(str) + } + }); + + /** + * @param {{name: string}} named + */ + function takeName(named) { return named.name; } + + takeName(x); + /** + * @type {number} + */ + var a = x.zip; + + /** + * @type {number} + */ + var b = x.houseNumber; + + const returnExemplar = () => x; + const needsExemplar = (_ = x) => void 0; + + const expected = /** @type {{name: string, readonly middleInit: string, readonly lastName: string, zip: number, readonly houseNumber: number, zipStr: string}} */(/** @type {*} */(null)); + + /** + * + * @param {typeof returnExemplar} a + * @param {typeof needsExemplar} b + */ + function match(a, b) {} + + match(() => expected, (x = expected) => void 0); + + module.exports = x; + \ No newline at end of file diff --git a/tests/baselines/reference/checkObjectDefineProperty.symbols b/tests/baselines/reference/checkObjectDefineProperty.symbols new file mode 100644 index 0000000000000..d3eea1a0a7461 --- /dev/null +++ b/tests/baselines/reference/checkObjectDefineProperty.symbols @@ -0,0 +1,197 @@ +=== tests/cases/conformance/jsdoc/validate.ts === +// Validate in TS as simple validations would usually be interpreted as more special assignments +import x = require("./"); +>x : Symbol(x, Decl(validate.ts, 0, 0)) + +x.name; +>x.name : Symbol(x["name"], Decl(index.js, 0, 13)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>name : Symbol(x["name"], Decl(index.js, 0, 13)) + +x.middleInit; +>x.middleInit : Symbol(x["middleInit"], Decl(index.js, 1, 71)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>middleInit : Symbol(x["middleInit"], Decl(index.js, 1, 71)) + +x.lastName; +>x.lastName : Symbol(x["lastName"], Decl(index.js, 2, 55)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>lastName : Symbol(x["lastName"], Decl(index.js, 2, 55)) + +x.zip; +>x.zip : Symbol(x["zip"], Decl(index.js, 3, 74)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>zip : Symbol(x["zip"], Decl(index.js, 3, 74)) + +x.houseNumber; +>x.houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) + +x.zipStr; +>x.zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) + +x.name = "Another"; +>x.name : Symbol(x["name"], Decl(index.js, 0, 13)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>name : Symbol(x["name"], Decl(index.js, 0, 13)) + +x.zip = 98123; +>x.zip : Symbol(x["zip"], Decl(index.js, 3, 74)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>zip : Symbol(x["zip"], Decl(index.js, 3, 74)) + +x.zipStr = "OK"; +>x.zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) + +x.lastName = "should fail"; +>x.lastName : Symbol(x["lastName"], Decl(index.js, 2, 55)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>lastName : Symbol(x["lastName"], Decl(index.js, 2, 55)) + +x.houseNumber = 12; // should also fail +>x.houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) + +x.zipStr = 12; // should fail +>x.zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>zipStr : Symbol(x["zipStr"], Decl(index.js, 5, 68)) + +x.middleInit = "R"; // should also fail +>x.middleInit : Symbol(x["middleInit"], Decl(index.js, 1, 71)) +>x : Symbol(x, Decl(validate.ts, 0, 0)) +>middleInit : Symbol(x["middleInit"], Decl(index.js, 1, 71)) + +=== tests/cases/conformance/jsdoc/index.js === +const x = {}; +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + +Object.defineProperty(x, "name", { value: "Charles", writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>value : Symbol(value, Decl(index.js, 1, 34)) +>writable : Symbol(writable, Decl(index.js, 1, 52)) + +Object.defineProperty(x, "middleInit", { value: "H" }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>value : Symbol(value, Decl(index.js, 2, 40)) + +Object.defineProperty(x, "lastName", { value: "Smith", writable: false }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>value : Symbol(value, Decl(index.js, 3, 38)) +>writable : Symbol(writable, Decl(index.js, 3, 54)) + +Object.defineProperty(x, "zip", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>get : Symbol(get, Decl(index.js, 4, 33)) +>set : Symbol(set, Decl(index.js, 4, 57)) +>_ : Symbol(_, Decl(index.js, 4, 62)) + +Object.defineProperty(x, "houseNumber", { get() { return 21.75 } }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>get : Symbol(get, Decl(index.js, 5, 41)) + +Object.defineProperty(x, "zipStr", { +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + + /** @param {string} str */ + set(str) { +>set : Symbol(set, Decl(index.js, 6, 36)) +>str : Symbol(str, Decl(index.js, 8, 8)) + + this.zip = Number(str) +>zip : Symbol(zip, Decl(index.js, 8, 14)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>str : Symbol(str, Decl(index.js, 8, 8)) + } +}); + +/** + * @param {{name: string}} named + */ +function takeName(named) { return named.name; } +>takeName : Symbol(takeName, Decl(index.js, 11, 3)) +>named : Symbol(named, Decl(index.js, 16, 18)) +>named.name : Symbol(name, Decl(index.js, 14, 12)) +>named : Symbol(named, Decl(index.js, 16, 18)) +>name : Symbol(name, Decl(index.js, 14, 12)) + +takeName(x); +>takeName : Symbol(takeName, Decl(index.js, 11, 3)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + +/** + * @type {number} + */ +var a = x.zip; +>a : Symbol(a, Decl(index.js, 22, 3)) +>x.zip : Symbol(x["zip"], Decl(index.js, 3, 74)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>zip : Symbol(x["zip"], Decl(index.js, 3, 74)) + +/** + * @type {number} + */ +var b = x.houseNumber; +>b : Symbol(b, Decl(index.js, 27, 3)) +>x.houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) +>houseNumber : Symbol(x["houseNumber"], Decl(index.js, 4, 83)) + +const returnExemplar = () => x; +>returnExemplar : Symbol(returnExemplar, Decl(index.js, 29, 5)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + +const needsExemplar = (_ = x) => void 0; +>needsExemplar : Symbol(needsExemplar, Decl(index.js, 30, 5)) +>_ : Symbol(_, Decl(index.js, 30, 23)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + +const expected = /** @type {{name: string, readonly middleInit: string, readonly lastName: string, zip: number, readonly houseNumber: number, zipStr: string}} */(/** @type {*} */(null)); +>expected : Symbol(expected, Decl(index.js, 32, 5)) + +/** + * + * @param {typeof returnExemplar} a + * @param {typeof needsExemplar} b + */ +function match(a, b) {} +>match : Symbol(match, Decl(index.js, 32, 186)) +>a : Symbol(a, Decl(index.js, 39, 15)) +>b : Symbol(b, Decl(index.js, 39, 17)) + +match(() => expected, (x = expected) => void 0); +>match : Symbol(match, Decl(index.js, 32, 186)) +>expected : Symbol(expected, Decl(index.js, 32, 5)) +>x : Symbol(x, Decl(index.js, 41, 23)) +>expected : Symbol(expected, Decl(index.js, 32, 5)) + +module.exports = x; +>module.exports : Symbol("tests/cases/conformance/jsdoc/index", Decl(index.js, 0, 0)) +>module : Symbol(export=, Decl(index.js, 41, 48)) +>exports : Symbol(export=, Decl(index.js, 41, 48)) +>x : Symbol(x, Decl(index.js, 0, 5), Decl(index.js, 1, 22)) + diff --git a/tests/baselines/reference/checkObjectDefineProperty.types b/tests/baselines/reference/checkObjectDefineProperty.types new file mode 100644 index 0000000000000..88a1e682dfc9e --- /dev/null +++ b/tests/baselines/reference/checkObjectDefineProperty.types @@ -0,0 +1,255 @@ +=== tests/cases/conformance/jsdoc/validate.ts === +// Validate in TS as simple validations would usually be interpreted as more special assignments +import x = require("./"); +>x : typeof x + +x.name; +>x.name : string +>x : typeof x +>name : string + +x.middleInit; +>x.middleInit : string +>x : typeof x +>middleInit : string + +x.lastName; +>x.lastName : string +>x : typeof x +>lastName : string + +x.zip; +>x.zip : number +>x : typeof x +>zip : number + +x.houseNumber; +>x.houseNumber : number +>x : typeof x +>houseNumber : number + +x.zipStr; +>x.zipStr : string +>x : typeof x +>zipStr : string + +x.name = "Another"; +>x.name = "Another" : "Another" +>x.name : string +>x : typeof x +>name : string +>"Another" : "Another" + +x.zip = 98123; +>x.zip = 98123 : 98123 +>x.zip : number +>x : typeof x +>zip : number +>98123 : 98123 + +x.zipStr = "OK"; +>x.zipStr = "OK" : "OK" +>x.zipStr : string +>x : typeof x +>zipStr : string +>"OK" : "OK" + +x.lastName = "should fail"; +>x.lastName = "should fail" : "should fail" +>x.lastName : any +>x : typeof x +>lastName : any +>"should fail" : "should fail" + +x.houseNumber = 12; // should also fail +>x.houseNumber = 12 : 12 +>x.houseNumber : any +>x : typeof x +>houseNumber : any +>12 : 12 + +x.zipStr = 12; // should fail +>x.zipStr = 12 : 12 +>x.zipStr : string +>x : typeof x +>zipStr : string +>12 : 12 + +x.middleInit = "R"; // should also fail +>x.middleInit = "R" : "R" +>x.middleInit : any +>x : typeof x +>middleInit : any +>"R" : "R" + +=== tests/cases/conformance/jsdoc/index.js === +const x = {}; +>x : typeof x +>{} : {} + +Object.defineProperty(x, "name", { value: "Charles", writable: true }); +>Object.defineProperty(x, "name", { value: "Charles", writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"name" : "name" +>{ value: "Charles", writable: true } : { value: string; writable: true; } +>value : string +>"Charles" : "Charles" +>writable : true +>true : true + +Object.defineProperty(x, "middleInit", { value: "H" }); +>Object.defineProperty(x, "middleInit", { value: "H" }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"middleInit" : "middleInit" +>{ value: "H" } : { value: string; } +>value : string +>"H" : "H" + +Object.defineProperty(x, "lastName", { value: "Smith", writable: false }); +>Object.defineProperty(x, "lastName", { value: "Smith", writable: false }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"lastName" : "lastName" +>{ value: "Smith", writable: false } : { value: string; writable: false; } +>value : string +>"Smith" : "Smith" +>writable : false +>false : false + +Object.defineProperty(x, "zip", { get() { return 98122 }, set(_) { /*ignore*/ } }); +>Object.defineProperty(x, "zip", { get() { return 98122 }, set(_) { /*ignore*/ } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"zip" : "zip" +>{ get() { return 98122 }, set(_) { /*ignore*/ } } : { get(): number; set(_: any): void; } +>get : () => number +>98122 : 98122 +>set : (_: any) => void +>_ : any + +Object.defineProperty(x, "houseNumber", { get() { return 21.75 } }); +>Object.defineProperty(x, "houseNumber", { get() { return 21.75 } }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"houseNumber" : "houseNumber" +>{ get() { return 21.75 } } : { get(): number; } +>get : () => number +>21.75 : 21.75 + +Object.defineProperty(x, "zipStr", { +>Object.defineProperty(x, "zipStr", { /** @param {string} str */ set(str) { this.zip = Number(str) }}) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>x : typeof x +>"zipStr" : "zipStr" +>{ /** @param {string} str */ set(str) { this.zip = Number(str) }} : { set(str: string): void; } + + /** @param {string} str */ + set(str) { +>set : (str: string) => void +>str : string + + this.zip = Number(str) +>this.zip = Number(str) : number +>this.zip : any +>this : any +>zip : any +>Number(str) : number +>Number : NumberConstructor +>str : string + } +}); + +/** + * @param {{name: string}} named + */ +function takeName(named) { return named.name; } +>takeName : (named: { name: string; }) => string +>named : { name: string; } +>named.name : string +>named : { name: string; } +>name : string + +takeName(x); +>takeName(x) : string +>takeName : (named: { name: string; }) => string +>x : typeof x + +/** + * @type {number} + */ +var a = x.zip; +>a : number +>x.zip : number +>x : typeof x +>zip : number + +/** + * @type {number} + */ +var b = x.houseNumber; +>b : number +>x.houseNumber : number +>x : typeof x +>houseNumber : number + +const returnExemplar = () => x; +>returnExemplar : () => typeof x +>() => x : () => typeof x +>x : typeof x + +const needsExemplar = (_ = x) => void 0; +>needsExemplar : (_?: typeof x) => undefined +>(_ = x) => void 0 : (_?: typeof x) => undefined +>_ : typeof x +>x : typeof x +>void 0 : undefined +>0 : 0 + +const expected = /** @type {{name: string, readonly middleInit: string, readonly lastName: string, zip: number, readonly houseNumber: number, zipStr: string}} */(/** @type {*} */(null)); +>expected : { name: string; readonly middleInit: string; readonly lastName: string; zip: number; readonly houseNumber: number; zipStr: string; } +>(/** @type {*} */(null)) : { name: string; readonly middleInit: string; readonly lastName: string; zip: number; readonly houseNumber: number; zipStr: string; } +>(null) : any +>null : null + +/** + * + * @param {typeof returnExemplar} a + * @param {typeof needsExemplar} b + */ +function match(a, b) {} +>match : (a: () => typeof x, b: (_?: typeof x) => undefined) => void +>a : () => typeof x +>b : (_?: typeof x) => undefined + +match(() => expected, (x = expected) => void 0); +>match(() => expected, (x = expected) => void 0) : void +>match : (a: () => typeof x, b: (_?: typeof x) => undefined) => void +>() => expected : () => { name: string; readonly middleInit: string; readonly lastName: string; zip: number; readonly houseNumber: number; zipStr: string; } +>expected : { name: string; readonly middleInit: string; readonly lastName: string; zip: number; readonly houseNumber: number; zipStr: string; } +>(x = expected) => void 0 : (x?: typeof x | undefined) => undefined +>x : typeof x | undefined +>expected : { name: string; readonly middleInit: string; readonly lastName: string; zip: number; readonly houseNumber: number; zipStr: string; } +>void 0 : undefined +>0 : 0 + +module.exports = x; +>module.exports = x : typeof x +>module.exports : typeof x +>module : { "tests/cases/conformance/jsdoc/index": typeof x; } +>exports : typeof x +>x : typeof x + diff --git a/tests/baselines/reference/checkOtherObjectAssignProperty.errors.txt b/tests/baselines/reference/checkOtherObjectAssignProperty.errors.txt new file mode 100644 index 0000000000000..146550d6fb62e --- /dev/null +++ b/tests/baselines/reference/checkOtherObjectAssignProperty.errors.txt @@ -0,0 +1,58 @@ +tests/cases/conformance/jsdoc/importer.js(3,5): error TS2339: Property 'other' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. +tests/cases/conformance/jsdoc/importer.js(4,5): error TS2339: Property 'prop' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. +tests/cases/conformance/jsdoc/importer.js(11,5): error TS2339: Property 'other' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. +tests/cases/conformance/jsdoc/importer.js(12,5): error TS2339: Property 'prop' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. +tests/cases/conformance/jsdoc/importer.js(13,5): error TS2540: Cannot assign to 'bad1' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/importer.js(14,5): error TS2540: Cannot assign to 'bad2' because it is a constant or a read-only property. +tests/cases/conformance/jsdoc/importer.js(15,5): error TS2540: Cannot assign to 'bad3' because it is a constant or a read-only property. + + +==== tests/cases/conformance/jsdoc/importer.js (7 errors) ==== + const mod = require("./mod1"); + mod.thing; + mod.other; + ~~~~~ +!!! error TS2339: Property 'other' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. + mod.prop; + ~~~~ +!!! error TS2339: Property 'prop' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. + mod.bad1; + mod.bad2; + mod.bad3; + + + mod.thing = 0; + mod.other = 0; + ~~~~~ +!!! error TS2339: Property 'other' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. + mod.prop = 0; + ~~~~ +!!! error TS2339: Property 'prop' does not exist on type 'typeof import("tests/cases/conformance/jsdoc/mod1")'. + mod.bad1 = 0; + ~~~~ +!!! error TS2540: Cannot assign to 'bad1' because it is a constant or a read-only property. + mod.bad2 = 0; + ~~~~ +!!! error TS2540: Cannot assign to 'bad2' because it is a constant or a read-only property. + mod.bad3 = 0; + ~~~~ +!!! error TS2540: Cannot assign to 'bad3' because it is a constant or a read-only property. + +==== tests/cases/conformance/jsdoc/mod1.js (0 errors) ==== + const obj = { value: 42, writable: true }; + Object.defineProperty(exports, "thing", obj); + + /** + * @type {string} + */ + let str = /** @type {string} */("other"); + Object.defineProperty(exports, str, { value: 42, writable: true }); + + const propName = "prop" + Object.defineProperty(exports, propName, { value: 42, writable: true }); + + + Object.defineProperty(exports, "bad1", { }); + Object.defineProperty(exports, "bad2", { get() { return 12 }, value: "no" }); + Object.defineProperty(exports, "bad3", { writable: true }); + \ No newline at end of file diff --git a/tests/baselines/reference/checkOtherObjectAssignProperty.symbols b/tests/baselines/reference/checkOtherObjectAssignProperty.symbols new file mode 100644 index 0000000000000..efc0a46315602 --- /dev/null +++ b/tests/baselines/reference/checkOtherObjectAssignProperty.symbols @@ -0,0 +1,121 @@ +=== tests/cases/conformance/jsdoc/importer.js === +const mod = require("./mod1"); +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>require : Symbol(require) +>"./mod1" : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) + +mod.thing; +>mod.thing : Symbol("thing", Decl(mod1.js, 0, 42)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>thing : Symbol("thing", Decl(mod1.js, 0, 42)) + +mod.other; +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) + +mod.prop; +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) + +mod.bad1; +>mod.bad1 : Symbol("bad1", Decl(mod1.js, 10, 72)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad1 : Symbol("bad1", Decl(mod1.js, 10, 72)) + +mod.bad2; +>mod.bad2 : Symbol("bad2", Decl(mod1.js, 13, 44)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad2 : Symbol("bad2", Decl(mod1.js, 13, 44)) + +mod.bad3; +>mod.bad3 : Symbol("bad3", Decl(mod1.js, 14, 77)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad3 : Symbol("bad3", Decl(mod1.js, 14, 77)) + + +mod.thing = 0; +>mod.thing : Symbol("thing", Decl(mod1.js, 0, 42)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>thing : Symbol("thing", Decl(mod1.js, 0, 42)) + +mod.other = 0; +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) + +mod.prop = 0; +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) + +mod.bad1 = 0; +>mod.bad1 : Symbol("bad1", Decl(mod1.js, 10, 72)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad1 : Symbol("bad1", Decl(mod1.js, 10, 72)) + +mod.bad2 = 0; +>mod.bad2 : Symbol("bad2", Decl(mod1.js, 13, 44)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad2 : Symbol("bad2", Decl(mod1.js, 13, 44)) + +mod.bad3 = 0; +>mod.bad3 : Symbol("bad3", Decl(mod1.js, 14, 77)) +>mod : Symbol(mod, Decl(importer.js, 0, 5), Decl(importer.js, 6, 9)) +>bad3 : Symbol("bad3", Decl(mod1.js, 14, 77)) + +=== tests/cases/conformance/jsdoc/mod1.js === +const obj = { value: 42, writable: true }; +>obj : Symbol(obj, Decl(mod1.js, 0, 5)) +>value : Symbol(value, Decl(mod1.js, 0, 13)) +>writable : Symbol(writable, Decl(mod1.js, 0, 24)) + +Object.defineProperty(exports, "thing", obj); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>obj : Symbol(obj, Decl(mod1.js, 0, 5)) + +/** + * @type {string} + */ +let str = /** @type {string} */("other"); +>str : Symbol(str, Decl(mod1.js, 6, 3)) + +Object.defineProperty(exports, str, { value: 42, writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>str : Symbol(str, Decl(mod1.js, 6, 3)) +>value : Symbol(value, Decl(mod1.js, 7, 37)) +>writable : Symbol(writable, Decl(mod1.js, 7, 48)) + +const propName = "prop" +>propName : Symbol(propName, Decl(mod1.js, 9, 5)) + +Object.defineProperty(exports, propName, { value: 42, writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>propName : Symbol(propName, Decl(mod1.js, 9, 5)) +>value : Symbol(value, Decl(mod1.js, 10, 42)) +>writable : Symbol(writable, Decl(mod1.js, 10, 53)) + + +Object.defineProperty(exports, "bad1", { }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) + +Object.defineProperty(exports, "bad2", { get() { return 12 }, value: "no" }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>get : Symbol(get, Decl(mod1.js, 14, 40)) +>value : Symbol(value, Decl(mod1.js, 14, 61)) + +Object.defineProperty(exports, "bad3", { writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0)) +>writable : Symbol(writable, Decl(mod1.js, 15, 40)) + diff --git a/tests/baselines/reference/checkOtherObjectAssignProperty.types b/tests/baselines/reference/checkOtherObjectAssignProperty.types new file mode 100644 index 0000000000000..d9b68d71745e8 --- /dev/null +++ b/tests/baselines/reference/checkOtherObjectAssignProperty.types @@ -0,0 +1,170 @@ +=== tests/cases/conformance/jsdoc/importer.js === +const mod = require("./mod1"); +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>require("./mod1") : typeof import("tests/cases/conformance/jsdoc/mod1") +>require : any +>"./mod1" : "./mod1" + +mod.thing; +>mod.thing : number +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>thing : number + +mod.other; +>mod.other : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>other : any + +mod.prop; +>mod.prop : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>prop : any + +mod.bad1; +>mod.bad1 : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad1 : any + +mod.bad2; +>mod.bad2 : string +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad2 : string + +mod.bad3; +>mod.bad3 : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad3 : any + + +mod.thing = 0; +>mod.thing = 0 : 0 +>mod.thing : number +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>thing : number +>0 : 0 + +mod.other = 0; +>mod.other = 0 : 0 +>mod.other : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>other : any +>0 : 0 + +mod.prop = 0; +>mod.prop = 0 : 0 +>mod.prop : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>prop : any +>0 : 0 + +mod.bad1 = 0; +>mod.bad1 = 0 : 0 +>mod.bad1 : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad1 : any +>0 : 0 + +mod.bad2 = 0; +>mod.bad2 = 0 : 0 +>mod.bad2 : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad2 : any +>0 : 0 + +mod.bad3 = 0; +>mod.bad3 = 0 : 0 +>mod.bad3 : any +>mod : typeof import("tests/cases/conformance/jsdoc/mod1") +>bad3 : any +>0 : 0 + +=== tests/cases/conformance/jsdoc/mod1.js === +const obj = { value: 42, writable: true }; +>obj : { value: number; writable: boolean; } +>{ value: 42, writable: true } : { value: number; writable: boolean; } +>value : number +>42 : 42 +>writable : boolean +>true : true + +Object.defineProperty(exports, "thing", obj); +>Object.defineProperty(exports, "thing", obj) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"thing" : "thing" +>obj : { value: number; writable: boolean; } + +/** + * @type {string} + */ +let str = /** @type {string} */("other"); +>str : string +>("other") : string +>"other" : "other" + +Object.defineProperty(exports, str, { value: 42, writable: true }); +>Object.defineProperty(exports, str, { value: 42, writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>str : string +>{ value: 42, writable: true } : { value: number; writable: true; } +>value : number +>42 : 42 +>writable : true +>true : true + +const propName = "prop" +>propName : "prop" +>"prop" : "prop" + +Object.defineProperty(exports, propName, { value: 42, writable: true }); +>Object.defineProperty(exports, propName, { value: 42, writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>propName : "prop" +>{ value: 42, writable: true } : { value: number; writable: true; } +>value : number +>42 : 42 +>writable : true +>true : true + + +Object.defineProperty(exports, "bad1", { }); +>Object.defineProperty(exports, "bad1", { }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"bad1" : "bad1" +>{ } : {} + +Object.defineProperty(exports, "bad2", { get() { return 12 }, value: "no" }); +>Object.defineProperty(exports, "bad2", { get() { return 12 }, value: "no" }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"bad2" : "bad2" +>{ get() { return 12 }, value: "no" } : { get(): number; value: string; } +>get : () => number +>12 : 12 +>value : string +>"no" : "no" + +Object.defineProperty(exports, "bad3", { writable: true }); +>Object.defineProperty(exports, "bad3", { writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>exports : typeof import("tests/cases/conformance/jsdoc/mod1") +>"bad3" : "bad3" +>{ writable: true } : { writable: true; } +>writable : true +>true : true + diff --git a/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.errors.txt b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.errors.txt new file mode 100644 index 0000000000000..d7c036abacf3a --- /dev/null +++ b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.errors.txt @@ -0,0 +1,23 @@ +tests/cases/compiler/namespacer.js(2,1): error TS2323: Cannot redeclare exported variable 'NS'. +tests/cases/compiler/namespacer.js(3,1): error TS2323: Cannot redeclare exported variable 'NS'. + + +==== tests/cases/compiler/index.js (0 errors) ==== + const _item = require("./namespacer"); + module.exports = 12; + Object.defineProperty(module, "exports", { value: "oh no" }); + +==== tests/cases/compiler/namespacey.js (0 errors) ==== + const A = {} + A.bar = class Q {} + module.exports = A; +==== tests/cases/compiler/namespacer.js (2 errors) ==== + const B = {} + B.NS = require("./namespacey"); + ~~~~ +!!! error TS2323: Cannot redeclare exported variable 'NS'. + Object.defineProperty(B, "NS", { value: "why though", writable: true }); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2323: Cannot redeclare exported variable 'NS'. + module.exports = B; + \ No newline at end of file diff --git a/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.symbols b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.symbols new file mode 100644 index 0000000000000..5b0883f227ac4 --- /dev/null +++ b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.symbols @@ -0,0 +1,59 @@ +=== tests/cases/compiler/index.js === +const _item = require("./namespacer"); +>_item : Symbol(_item, Decl(index.js, 0, 5)) +>require : Symbol(require) +>"./namespacer" : Symbol("tests/cases/compiler/namespacer", Decl(namespacer.js, 0, 0)) + +module.exports = 12; +>module.exports : Symbol("tests/cases/compiler/index", Decl(index.js, 0, 0)) +>module : Symbol(export=, Decl(index.js, 0, 38)) +>exports : Symbol(export=, Decl(index.js, 0, 38)) + +Object.defineProperty(module, "exports", { value: "oh no" }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>module : Symbol(module, Decl(index.js, 0, 38), Decl(index.js, 2, 22)) +>value : Symbol(value, Decl(index.js, 2, 42)) + +=== tests/cases/compiler/namespacey.js === +const A = {} +>A : Symbol(A, Decl(namespacey.js, 0, 5), Decl(namespacey.js, 0, 12)) + +A.bar = class Q {} +>A.bar : Symbol(A.bar, Decl(namespacey.js, 0, 12)) +>A : Symbol(A, Decl(namespacey.js, 0, 5), Decl(namespacey.js, 0, 12)) +>bar : Symbol(A.bar, Decl(namespacey.js, 0, 12)) +>Q : Symbol(Q, Decl(namespacey.js, 1, 7)) + +module.exports = A; +>module.exports : Symbol("tests/cases/compiler/namespacey", Decl(namespacey.js, 0, 0)) +>module : Symbol(export=, Decl(namespacey.js, 1, 18)) +>exports : Symbol(export=, Decl(namespacey.js, 1, 18)) +>A : Symbol(A, Decl(namespacey.js, 0, 5), Decl(namespacey.js, 0, 12)) + +=== tests/cases/compiler/namespacer.js === +const B = {} +>B : Symbol(B, Decl(namespacer.js, 0, 5), Decl(namespacer.js, 0, 12)) + +B.NS = require("./namespacey"); +>B.NS : Symbol(B.NS, Decl(namespacer.js, 0, 12), Decl(namespacer.js, 1, 31)) +>B : Symbol(B, Decl(namespacer.js, 0, 5), Decl(namespacer.js, 0, 12)) +>NS : Symbol(B.NS, Decl(namespacer.js, 0, 12), Decl(namespacer.js, 1, 31)) +>require : Symbol(require) +>"./namespacey" : Symbol("tests/cases/compiler/namespacey", Decl(namespacey.js, 0, 0)) + +Object.defineProperty(B, "NS", { value: "why though", writable: true }); +>Object.defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>defineProperty : Symbol(ObjectConstructor.defineProperty, Decl(lib.es5.d.ts, --, --)) +>B : Symbol(B, Decl(namespacer.js, 0, 5), Decl(namespacer.js, 0, 12)) +>value : Symbol(value, Decl(namespacer.js, 2, 32)) +>writable : Symbol(writable, Decl(namespacer.js, 2, 53)) + +module.exports = B; +>module.exports : Symbol("tests/cases/compiler/namespacer", Decl(namespacer.js, 0, 0)) +>module : Symbol(export=, Decl(namespacer.js, 2, 72)) +>exports : Symbol(export=, Decl(namespacer.js, 2, 72)) +>B : Symbol(B, Decl(namespacer.js, 0, 5), Decl(namespacer.js, 0, 12)) + diff --git a/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.types b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.types new file mode 100644 index 0000000000000..ebd6f7ba4342d --- /dev/null +++ b/tests/baselines/reference/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.types @@ -0,0 +1,79 @@ +=== tests/cases/compiler/index.js === +const _item = require("./namespacer"); +>_item : typeof B +>require("./namespacer") : typeof B +>require : any +>"./namespacer" : "./namespacer" + +module.exports = 12; +>module.exports = 12 : number +>module.exports : number +>module : typeof module +>exports : number +>12 : 12 + +Object.defineProperty(module, "exports", { value: "oh no" }); +>Object.defineProperty(module, "exports", { value: "oh no" }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>module : typeof module +>"exports" : "exports" +>{ value: "oh no" } : { value: string; } +>value : string +>"oh no" : "oh no" + +=== tests/cases/compiler/namespacey.js === +const A = {} +>A : typeof A +>{} : {} + +A.bar = class Q {} +>A.bar = class Q {} : typeof Q +>A.bar : typeof Q +>A : typeof A +>bar : typeof Q +>class Q {} : typeof Q +>Q : typeof Q + +module.exports = A; +>module.exports = A : typeof A +>module.exports : typeof A +>module : { "tests/cases/compiler/namespacey": typeof A; } +>exports : typeof A +>A : typeof A + +=== tests/cases/compiler/namespacer.js === +const B = {} +>B : typeof B +>{} : {} + +B.NS = require("./namespacey"); +>B.NS = require("./namespacey") : typeof A +>B.NS : string | typeof A +>B : typeof B +>NS : string | typeof A +>require("./namespacey") : typeof A +>require : any +>"./namespacey" : "./namespacey" + +Object.defineProperty(B, "NS", { value: "why though", writable: true }); +>Object.defineProperty(B, "NS", { value: "why though", writable: true }) : any +>Object.defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>Object : ObjectConstructor +>defineProperty : (o: any, p: string | number | symbol, attributes: PropertyDescriptor & ThisType) => any +>B : typeof B +>"NS" : "NS" +>{ value: "why though", writable: true } : { value: string; writable: true; } +>value : string +>"why though" : "why though" +>writable : true +>true : true + +module.exports = B; +>module.exports = B : typeof B +>module.exports : typeof B +>module : { "tests/cases/compiler/namespacer": typeof B; } +>exports : typeof B +>B : typeof B + diff --git a/tests/cases/compiler/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.ts b/tests/cases/compiler/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.ts new file mode 100644 index 0000000000000..a0c0b325adf67 --- /dev/null +++ b/tests/cases/compiler/ensureNoCrashExportAssignmentDefineProperrtyPotentialMerge.ts @@ -0,0 +1,17 @@ +// @allowJs: true +// @noEmit: true +// @checkJs: true +// @filename: namespacey.js +const A = {} +A.bar = class Q {} +module.exports = A; +// @filename: namespacer.js +const B = {} +B.NS = require("./namespacey"); +Object.defineProperty(B, "NS", { value: "why though", writable: true }); +module.exports = B; + +// @filename: index.js +const _item = require("./namespacer"); +module.exports = 12; +Object.defineProperty(module, "exports", { value: "oh no" }); diff --git a/tests/cases/conformance/jsdoc/checkExportsObjectAssignProperty.ts b/tests/cases/conformance/jsdoc/checkExportsObjectAssignProperty.ts new file mode 100644 index 0000000000000..132fef0451028 --- /dev/null +++ b/tests/cases/conformance/jsdoc/checkExportsObjectAssignProperty.ts @@ -0,0 +1,82 @@ +// @allowJs: true +// @noEmit: true +// @strict: true +// @checkJs: true +// @filename: mod1.js +Object.defineProperty(exports, "thing", { value: 42, writable: true }); +Object.defineProperty(exports, "readonlyProp", { value: "Smith", writable: false }); +Object.defineProperty(exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +Object.defineProperty(exports, "readonlyAccessor", { get() { return 21.75 } }); +Object.defineProperty(exports, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } +}); + +// @filename: mod2.js +Object.defineProperty(module.exports, "thing", { value: "yes", writable: true }); +Object.defineProperty(module.exports, "readonlyProp", { value: "Smith", writable: false }); +Object.defineProperty(module.exports, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +Object.defineProperty(module.exports, "readonlyAccessor", { get() { return 21.75 } }); +Object.defineProperty(module.exports, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } +}); + +// @filename: index.js + +/** + * @type {number} + */ +const q = require("./mod1").thing; + +/** + * @type {string} + */ +const u = require("./mod2").thing; + +// @filename: validator.ts +import "./"; + +import m1 = require("./mod1"); + +m1.thing; +m1.readonlyProp; +m1.rwAccessors; +m1.readonlyAccessor; +m1.setonlyAccessor; + +// allowed assignments +m1.thing = 10; +m1.rwAccessors = 11; +m1.setonlyAccessor = "yes"; + +// disallowed assignments +m1.readonlyProp = "name"; +m1.readonlyAccessor = 12; +m1.thing = "no"; +m1.rwAccessors = "no"; +m1.setonlyAccessor = 0; + +import m2 = require("./mod2"); + +m2.thing; +m2.readonlyProp; +m2.rwAccessors; +m2.readonlyAccessor; +m2.setonlyAccessor; + +// allowed assignments +m2.thing = "ok"; +m2.rwAccessors = 11; +m2.setonlyAccessor = "yes"; + +// disallowed assignments +m2.readonlyProp = "name"; +m2.readonlyAccessor = 12; +m2.thing = 0; +m2.rwAccessors = "no"; +m2.setonlyAccessor = 0; diff --git a/tests/cases/conformance/jsdoc/checkExportsObjectAssignPrototypeProperty.ts b/tests/cases/conformance/jsdoc/checkExportsObjectAssignPrototypeProperty.ts new file mode 100644 index 0000000000000..9518e05264654 --- /dev/null +++ b/tests/cases/conformance/jsdoc/checkExportsObjectAssignPrototypeProperty.ts @@ -0,0 +1,52 @@ +// @allowJs: true +// @noEmit: true +// @strict: true +// @checkJs: true +// @filename: mod1.js +/** + * @constructor + * @param {string} name + */ +function Person(name) { + this.name = name; +} +Person.prototype.describe = function () { + return "Person called " + this.name; +}; +Object.defineProperty(Person.prototype, "thing", { value: 42, writable: true }); +Object.defineProperty(Person.prototype, "readonlyProp", { value: "Smith", writable: false }); +Object.defineProperty(Person.prototype, "rwAccessors", { get() { return 98122 }, set(_) { /*ignore*/ } }); +Object.defineProperty(Person.prototype, "readonlyAccessor", { get() { return 21.75 } }); +Object.defineProperty(Person.prototype, "setonlyAccessor", { + /** @param {string} str */ + set(str) { + this.rwAccessors = Number(str) + } +}); +module.exports = Person; + +// @filename: validator.ts +import "./"; + +import Person = require("./mod1"); + +const m1 = new Person("Name") + +m1.thing; +m1.readonlyProp; +m1.rwAccessors; +m1.readonlyAccessor; +m1.setonlyAccessor; + +// allowed assignments +m1.thing = 10; +m1.rwAccessors = 11; +m1.setonlyAccessor = "yes"; + +// disallowed assignments +m1.readonlyProp = "name"; +m1.readonlyAccessor = 12; +m1.thing = "no"; +m1.rwAccessors = "no"; +m1.setonlyAccessor = 0; + diff --git a/tests/cases/conformance/jsdoc/checkObjectDefineProperty.ts b/tests/cases/conformance/jsdoc/checkObjectDefineProperty.ts new file mode 100644 index 0000000000000..d0ba377b000c6 --- /dev/null +++ b/tests/cases/conformance/jsdoc/checkObjectDefineProperty.ts @@ -0,0 +1,68 @@ +// @allowJs: true +// @noEmit: true +// @strict: true +// @checkJs: true +// @filename: index.js +const x = {}; +Object.defineProperty(x, "name", { value: "Charles", writable: true }); +Object.defineProperty(x, "middleInit", { value: "H" }); +Object.defineProperty(x, "lastName", { value: "Smith", writable: false }); +Object.defineProperty(x, "zip", { get() { return 98122 }, set(_) { /*ignore*/ } }); +Object.defineProperty(x, "houseNumber", { get() { return 21.75 } }); +Object.defineProperty(x, "zipStr", { + /** @param {string} str */ + set(str) { + this.zip = Number(str) + } +}); + +/** + * @param {{name: string}} named + */ +function takeName(named) { return named.name; } + +takeName(x); +/** + * @type {number} + */ +var a = x.zip; + +/** + * @type {number} + */ +var b = x.houseNumber; + +const returnExemplar = () => x; +const needsExemplar = (_ = x) => void 0; + +const expected = /** @type {{name: string, readonly middleInit: string, readonly lastName: string, zip: number, readonly houseNumber: number, zipStr: string}} */(/** @type {*} */(null)); + +/** + * + * @param {typeof returnExemplar} a + * @param {typeof needsExemplar} b + */ +function match(a, b) {} + +match(() => expected, (x = expected) => void 0); + +module.exports = x; + +// @filename: validate.ts +// Validate in TS as simple validations would usually be interpreted as more special assignments +import x = require("./"); +x.name; +x.middleInit; +x.lastName; +x.zip; +x.houseNumber; +x.zipStr; + +x.name = "Another"; +x.zip = 98123; +x.zipStr = "OK"; + +x.lastName = "should fail"; +x.houseNumber = 12; // should also fail +x.zipStr = 12; // should fail +x.middleInit = "R"; // should also fail diff --git a/tests/cases/conformance/jsdoc/checkOtherObjectAssignProperty.ts b/tests/cases/conformance/jsdoc/checkOtherObjectAssignProperty.ts new file mode 100644 index 0000000000000..a7bccc65283a0 --- /dev/null +++ b/tests/cases/conformance/jsdoc/checkOtherObjectAssignProperty.ts @@ -0,0 +1,39 @@ +// @allowJs: true +// @noEmit: true +// @strict: true +// @checkJs: true +// @filename: mod1.js + +const obj = { value: 42, writable: true }; +Object.defineProperty(exports, "thing", obj); + +/** + * @type {string} + */ +let str = /** @type {string} */("other"); +Object.defineProperty(exports, str, { value: 42, writable: true }); + +const propName = "prop" +Object.defineProperty(exports, propName, { value: 42, writable: true }); + + +Object.defineProperty(exports, "bad1", { }); +Object.defineProperty(exports, "bad2", { get() { return 12 }, value: "no" }); +Object.defineProperty(exports, "bad3", { writable: true }); + +// @filename: importer.js +const mod = require("./mod1"); +mod.thing; +mod.other; +mod.prop; +mod.bad1; +mod.bad2; +mod.bad3; + + +mod.thing = 0; +mod.other = 0; +mod.prop = 0; +mod.bad1 = 0; +mod.bad2 = 0; +mod.bad3 = 0; diff --git a/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile1.ts b/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile1.ts new file mode 100644 index 0000000000000..4dd0654a897df --- /dev/null +++ b/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile1.ts @@ -0,0 +1,20 @@ +/// + +// @allowJs: true +// @allowSyntheticDefaultImports: true + +// @Filename: /a.js +////exports.__esModule = true; +////exports.default = f; +/////** +//// * Run this function +//// * @param {string} t +//// */ +////function f(t) {} + +// @Filename: /b.js +////import f from "./a" +/////**/f + +verify.quickInfoAt("", `(alias) (property) f: (t: string) => void +import f`, "Run this function"); // Passes \ No newline at end of file diff --git a/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile2.ts b/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile2.ts new file mode 100644 index 0000000000000..0cfb4e684542c --- /dev/null +++ b/tests/cases/fourslash/syntheticImportFromBabelGeneratedFile2.ts @@ -0,0 +1,22 @@ +/// + +// @allowJs: true +// @allowSyntheticDefaultImports: true + +// @Filename: /a.js +////Object.defineProperty(exports, "__esModule", { +//// value: true +////}); +////exports.default = f; +/////** +//// * Run this function +//// * @param {string} t +//// */ +////function f(t) {} + +// @Filename: /b.js +////import f from "./a" +/////**/f + +verify.quickInfoAt("", `(alias) (property) f: (t: string) => void +import f`, "Run this function"); // Passes \ No newline at end of file