From 50ccd91263b5a3c7f53749e9bde3ca4520e5af0b Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 13 Aug 2018 16:21:37 -0700 Subject: [PATCH 1/2] Baseline the require of json file in js file --- .../requireOfJsonFileInJsFile.errors.txt | 33 ++++++++++ .../requireOfJsonFileInJsFile.symbols | 50 +++++++++++++++ .../reference/requireOfJsonFileInJsFile.types | 63 +++++++++++++++++++ .../compiler/requireOfJsonFileInJsFile.ts | 26 ++++++++ 4 files changed, 172 insertions(+) create mode 100644 tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt create mode 100644 tests/baselines/reference/requireOfJsonFileInJsFile.symbols create mode 100644 tests/baselines/reference/requireOfJsonFileInJsFile.types create mode 100644 tests/cases/compiler/requireOfJsonFileInJsFile.ts diff --git a/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt b/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt new file mode 100644 index 00000000000..39236816e57 --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt @@ -0,0 +1,33 @@ +/user.js(2,7): error TS2339: Property 'b' does not exist on type '{ "a": number; }'. +/user.js(9,7): error TS2339: Property 'b' does not exist on type '{ "a": number; }'. +/user.js(12,7): error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'. + Property 'b' is missing in type '{ a: number; }'. + + +==== /user.js (3 errors) ==== + const json0 = require("./json.json"); + json0.b; // Error (good) + ~ +!!! error TS2339: Property 'b' does not exist on type '{ "a": number; }'. + + /** @type {{ b: number }} */ + const json1 = require("./json.json"); // No error (bad) + json1.b; // No error (OK since that's the type annotation) + + const js0 = require("./js.js"); + json0.b; // Error (good) + ~ +!!! error TS2339: Property 'b' does not exist on type '{ "a": number; }'. + + /** @type {{ b: number }} */ + const js1 = require("./js.js"); // Error (good) + ~~~ +!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'. +!!! error TS2322: Property 'b' is missing in type '{ a: number; }'. + js1.b; +==== /json.json (0 errors) ==== + { "a": 0 } + +==== /js.js (0 errors) ==== + module.exports = { a: 0 }; + \ No newline at end of file diff --git a/tests/baselines/reference/requireOfJsonFileInJsFile.symbols b/tests/baselines/reference/requireOfJsonFileInJsFile.symbols new file mode 100644 index 00000000000..2a1e9b6ebd3 --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileInJsFile.symbols @@ -0,0 +1,50 @@ +=== /user.js === +const json0 = require("./json.json"); +>json0 : Symbol(json0, Decl(user.js, 0, 5)) +>require : Symbol(require) +>"./json.json" : Symbol("/json", Decl(json.json, 0, 0)) + +json0.b; // Error (good) +>json0 : Symbol(json0, Decl(user.js, 0, 5)) + +/** @type {{ b: number }} */ +const json1 = require("./json.json"); // No error (bad) +>json1 : Symbol(json1, Decl(user.js, 4, 5)) +>require : Symbol(require) +>"./json.json" : Symbol("/json", Decl(json.json, 0, 0)) + +json1.b; // No error (OK since that's the type annotation) +>json1.b : Symbol(b, Decl(user.js, 3, 12)) +>json1 : Symbol(json1, Decl(user.js, 4, 5)) +>b : Symbol(b, Decl(user.js, 3, 12)) + +const js0 = require("./js.js"); +>js0 : Symbol(js0, Decl(user.js, 7, 5)) +>require : Symbol(require) +>"./js.js" : Symbol("/js", Decl(js.js, 0, 0)) + +json0.b; // Error (good) +>json0 : Symbol(json0, Decl(user.js, 0, 5)) + +/** @type {{ b: number }} */ +const js1 = require("./js.js"); // Error (good) +>js1 : Symbol(js1, Decl(user.js, 11, 5)) +>require : Symbol(require) +>"./js.js" : Symbol("/js", Decl(js.js, 0, 0)) + +js1.b; +>js1.b : Symbol(b, Decl(user.js, 10, 12)) +>js1 : Symbol(js1, Decl(user.js, 11, 5)) +>b : Symbol(b, Decl(user.js, 10, 12)) + +=== /json.json === +{ "a": 0 } +>"a" : Symbol("a", Decl(json.json, 0, 1)) + +=== /js.js === +module.exports = { a: 0 }; +>module.exports : Symbol("/js", Decl(js.js, 0, 0)) +>module : Symbol(export=, Decl(js.js, 0, 0)) +>exports : Symbol(export=, Decl(js.js, 0, 0)) +>a : Symbol(a, Decl(js.js, 0, 18)) + diff --git a/tests/baselines/reference/requireOfJsonFileInJsFile.types b/tests/baselines/reference/requireOfJsonFileInJsFile.types new file mode 100644 index 00000000000..b069c87c395 --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileInJsFile.types @@ -0,0 +1,63 @@ +=== /user.js === +const json0 = require("./json.json"); +>json0 : { "a": number; } +>require("./json.json") : { "a": number; } +>require : any +>"./json.json" : "./json.json" + +json0.b; // Error (good) +>json0.b : any +>json0 : { "a": number; } +>b : any + +/** @type {{ b: number }} */ +const json1 = require("./json.json"); // No error (bad) +>json1 : { b: number; } +>require("./json.json") : { "a": number; } +>require : any +>"./json.json" : "./json.json" + +json1.b; // No error (OK since that's the type annotation) +>json1.b : number +>json1 : { b: number; } +>b : number + +const js0 = require("./js.js"); +>js0 : { a: number; } +>require("./js.js") : { a: number; } +>require : any +>"./js.js" : "./js.js" + +json0.b; // Error (good) +>json0.b : any +>json0 : { "a": number; } +>b : any + +/** @type {{ b: number }} */ +const js1 = require("./js.js"); // Error (good) +>js1 : { b: number; } +>require("./js.js") : { a: number; } +>require : any +>"./js.js" : "./js.js" + +js1.b; +>js1.b : number +>js1 : { b: number; } +>b : number + +=== /json.json === +{ "a": 0 } +>{ "a": 0 } : { "a": number; } +>"a" : number +>0 : 0 + +=== /js.js === +module.exports = { a: 0 }; +>module.exports = { a: 0 } : { a: number; } +>module.exports : { a: number; } +>module : { "/js": { a: number; }; } +>exports : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + diff --git a/tests/cases/compiler/requireOfJsonFileInJsFile.ts b/tests/cases/compiler/requireOfJsonFileInJsFile.ts new file mode 100644 index 00000000000..be8a3b00746 --- /dev/null +++ b/tests/cases/compiler/requireOfJsonFileInJsFile.ts @@ -0,0 +1,26 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @strict: true +// @resolveJsonModule: true + +// @Filename: /json.json +{ "a": 0 } + +// @Filename: /js.js +module.exports = { a: 0 }; + +// @Filename: /user.js +const json0 = require("./json.json"); +json0.b; // Error (good) + +/** @type {{ b: number }} */ +const json1 = require("./json.json"); // No error (bad) +json1.b; // No error (OK since that's the type annotation) + +const js0 = require("./js.js"); +json0.b; // Error (good) + +/** @type {{ b: number }} */ +const js1 = require("./js.js"); // Error (good) +js1.b; \ No newline at end of file From 9eb0c9a88fa4f1cc5e83a314e6710079f67aa4ca Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 14 Aug 2018 13:24:39 -0700 Subject: [PATCH 2/2] Use widened type (just like importing using module.exports = in js file) Fixes #26429 --- src/compiler/checker.ts | 9 ++++++++- .../reference/requireOfJsonFileInJsFile.errors.txt | 7 ++++++- .../baselines/reference/requireOfJsonFileTypes.types | 12 ++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da1af15dfa4..83cd2c1fe5c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5092,7 +5092,14 @@ namespace ts { // Handle export default expressions if (isSourceFile(declaration)) { const jsonSourceFile = cast(declaration, isJsonSourceFile); - return jsonSourceFile.statements.length ? checkExpression(jsonSourceFile.statements[0].expression) : emptyObjectType; + if (!jsonSourceFile.statements.length) { + return emptyObjectType; + } + const type = getWidenedLiteralType(checkExpression(jsonSourceFile.statements[0].expression)); + if (type.flags & TypeFlags.Object) { + return getRegularTypeOfObjectLiteral(type); + } + return type; } if (declaration.kind === SyntaxKind.ExportAssignment) { return checkExpression((declaration).expression); diff --git a/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt b/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt index 39236816e57..dcc976a1b5b 100644 --- a/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt +++ b/tests/baselines/reference/requireOfJsonFileInJsFile.errors.txt @@ -1,10 +1,12 @@ /user.js(2,7): error TS2339: Property 'b' does not exist on type '{ "a": number; }'. +/user.js(5,7): error TS2322: Type '{ "a": number; }' is not assignable to type '{ b: number; }'. + Property 'b' is missing in type '{ "a": number; }'. /user.js(9,7): error TS2339: Property 'b' does not exist on type '{ "a": number; }'. /user.js(12,7): error TS2322: Type '{ a: number; }' is not assignable to type '{ b: number; }'. Property 'b' is missing in type '{ a: number; }'. -==== /user.js (3 errors) ==== +==== /user.js (4 errors) ==== const json0 = require("./json.json"); json0.b; // Error (good) ~ @@ -12,6 +14,9 @@ /** @type {{ b: number }} */ const json1 = require("./json.json"); // No error (bad) + ~~~~~ +!!! error TS2322: Type '{ "a": number; }' is not assignable to type '{ b: number; }'. +!!! error TS2322: Property 'b' is missing in type '{ "a": number; }'. json1.b; // No error (OK since that's the type annotation) const js0 = require("./js.js"); diff --git a/tests/baselines/reference/requireOfJsonFileTypes.types b/tests/baselines/reference/requireOfJsonFileTypes.types index d9cd38cd58f..d4587696fc7 100644 --- a/tests/baselines/reference/requireOfJsonFileTypes.types +++ b/tests/baselines/reference/requireOfJsonFileTypes.types @@ -6,10 +6,10 @@ import c = require('./c.json'); >c : (string | null)[] import d = require('./d.json'); ->d : "dConfig" +>d : string import e = require('./e.json'); ->e : -10 +>e : number import f = require('./f.json'); >f : number[] @@ -64,14 +64,14 @@ const stringOrNumberOrNull: string | number | null = c[0]; >0 : 0 stringLiteral = d; ->stringLiteral = d : "dConfig" +>stringLiteral = d : string >stringLiteral : string ->d : "dConfig" +>d : string numberLiteral = e; ->numberLiteral = e : -10 +>numberLiteral = e : number >numberLiteral : number ->e : -10 +>e : number numberLiteral = f[0]; >numberLiteral = f[0] : number