diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c3faa45cd5420..682271113d863 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7310,11 +7310,7 @@ namespace ts { if (!declaration.statements.length) { return emptyObjectType; } - const type = getWidenedLiteralType(checkExpression(declaration.statements[0].expression)); - if (type.flags & TypeFlags.Object) { - return getRegularTypeOfObjectLiteral(type); - } - return type; + return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression))); } // Handle variable, parameter or property @@ -14806,7 +14802,7 @@ namespace ts { // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. // However, using an object-literal error message will be very confusing to the users so we give different a message. // TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages) - if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration)) { + if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) { // Note that extraneous children (as in `extra`) don't pass this check, // since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute. errorNode = prop.valueDeclaration.name; @@ -14817,7 +14813,7 @@ namespace ts { // use the property's value declaration if the property is assigned inside the literal itself const objectLiteralDeclaration = source.symbol && firstOrUndefined(source.symbol.declarations); let suggestion; - if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration)) { + if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) { const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike; Debug.assertNode(propDeclaration, isObjectLiteralElementLike); diff --git a/tests/baselines/reference/jsDeclarationsJson.types b/tests/baselines/reference/jsDeclarationsJson.types index 9a0a94677ef98..3294656ba3302 100644 --- a/tests/baselines/reference/jsDeclarationsJson.types +++ b/tests/baselines/reference/jsDeclarationsJson.types @@ -1,7 +1,7 @@ === tests/cases/conformance/jsdoc/declarations/index.js === const j = require("./obj.json"); >j : { x: number; y: number; obj: { items: ({ x: number; y?: undefined; err?: undefined; } | { x: number; y: number; err?: undefined; } | { x: number; err: boolean; y?: undefined; })[]; }; } ->require("./obj.json") : { x: number; y: number; obj: { items: ({ x: number; } | { x: number; y: number; } | { x: number; err: boolean; })[]; }; } +>require("./obj.json") : { x: number; y: number; obj: { items: ({ x: number; y?: undefined; err?: undefined; } | { x: number; y: number; err?: undefined; } | { x: number; err: boolean; y?: undefined; })[]; }; } >require : any >"./obj.json" : "./obj.json" diff --git a/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.js b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.js new file mode 100644 index 0000000000000..a76ac7c0be10f --- /dev/null +++ b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.js @@ -0,0 +1,42 @@ +//// [tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts] //// + +//// [index.ts] +import data from "./data.json"; + +interface Foo { + str: string; +} + +fn(data.foo); +fn(data.foo); // <-- shouldn't error! + +function fn(arg: Foo[]) { } +//// [data.json] +{ + "foo": [ + { + "bool": true, + "str": "123" + } + ] +} + +//// [data.json] +{ + "foo": [ + { + "bool": true, + "str": "123" + } + ] +} +//// [index.js] +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +exports.__esModule = true; +var data_json_1 = __importDefault(require("./data.json")); +fn(data_json_1["default"].foo); +fn(data_json_1["default"].foo); // <-- shouldn't error! +function fn(arg) { } diff --git a/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.symbols b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.symbols new file mode 100644 index 0000000000000..2005966a89a5a --- /dev/null +++ b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.symbols @@ -0,0 +1,41 @@ +=== tests/cases/compiler/index.ts === +import data from "./data.json"; +>data : Symbol(data, Decl(index.ts, 0, 6)) + +interface Foo { +>Foo : Symbol(Foo, Decl(index.ts, 0, 31)) + + str: string; +>str : Symbol(Foo.str, Decl(index.ts, 2, 15)) +} + +fn(data.foo); +>fn : Symbol(fn, Decl(index.ts, 7, 13)) +>data.foo : Symbol("foo", Decl(data.json, 0, 1)) +>data : Symbol(data, Decl(index.ts, 0, 6)) +>foo : Symbol("foo", Decl(data.json, 0, 1)) + +fn(data.foo); // <-- shouldn't error! +>fn : Symbol(fn, Decl(index.ts, 7, 13)) +>data.foo : Symbol("foo", Decl(data.json, 0, 1)) +>data : Symbol(data, Decl(index.ts, 0, 6)) +>foo : Symbol("foo", Decl(data.json, 0, 1)) + +function fn(arg: Foo[]) { } +>fn : Symbol(fn, Decl(index.ts, 7, 13)) +>arg : Symbol(arg, Decl(index.ts, 9, 12)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 31)) + +=== tests/cases/compiler/data.json === +{ + "foo": [ +>"foo" : Symbol("foo", Decl(data.json, 0, 1)) + { + "bool": true, +>"bool" : Symbol("bool", Decl(data.json, 2, 7)) + + "str": "123" +>"str" : Symbol("str", Decl(data.json, 3, 21)) + } + ] +} diff --git a/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.types b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.types new file mode 100644 index 0000000000000..a4e33505a9ffa --- /dev/null +++ b/tests/baselines/reference/jsonFileImportChecksCallCorrectlyTwice.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/index.ts === +import data from "./data.json"; +>data : { foo: { bool: boolean; str: string; }[]; } + +interface Foo { + str: string; +>str : string +} + +fn(data.foo); +>fn(data.foo) : void +>fn : (arg: Foo[]) => void +>data.foo : { bool: boolean; str: string; }[] +>data : { foo: { bool: boolean; str: string; }[]; } +>foo : { bool: boolean; str: string; }[] + +fn(data.foo); // <-- shouldn't error! +>fn(data.foo) : void +>fn : (arg: Foo[]) => void +>data.foo : { bool: boolean; str: string; }[] +>data : { foo: { bool: boolean; str: string; }[]; } +>foo : { bool: boolean; str: string; }[] + +function fn(arg: Foo[]) { } +>fn : (arg: Foo[]) => void +>arg : Foo[] + +=== tests/cases/compiler/data.json === +{ +>{ "foo": [ { "bool": true, "str": "123" } ]} : { foo: { bool: boolean; str: string; }[]; } + + "foo": [ +>"foo" : { bool: boolean; str: string; }[] +>[ { "bool": true, "str": "123" } ] : { bool: boolean; str: string; }[] + { +>{ "bool": true, "str": "123" } : { bool: boolean; str: string; } + + "bool": true, +>"bool" : boolean +>true : true + + "str": "123" +>"str" : string +>"123" : "123" + } + ] +} diff --git a/tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts b/tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts new file mode 100644 index 0000000000000..67bdeda20502b --- /dev/null +++ b/tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts @@ -0,0 +1,24 @@ +// @esModuleInterop: true +// @resolveJsonModule: true +// @strict: true +// @outDir: dist +// @filename: index.ts +import data from "./data.json"; + +interface Foo { + str: string; +} + +fn(data.foo); +fn(data.foo); // <-- shouldn't error! + +function fn(arg: Foo[]) { } +// @filename: data.json +{ + "foo": [ + { + "bool": true, + "str": "123" + } + ] +} \ No newline at end of file