From cc989dfb26ee9318b6a0e9d78c722f58d613ebbd Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 21 Oct 2018 19:28:11 -0400 Subject: [PATCH 1/7] Sanity check TypeScript config --- .../scripts/utils/verifyTypeScriptSetup.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js index 4b16a0b5a48..1da25d17090 100644 --- a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js +++ b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js @@ -12,6 +12,11 @@ const chalk = require('chalk'); const fs = require('fs'); const resolve = require('resolve'); const paths = require('../../config/paths'); +const os = require('os'); + +function writeJson(fileName, object) { + fs.writeFileSync(fileName, JSON.stringify(object, null, 2) + os.EOL); +} function verifyTypeScriptSetup() { if (!fs.existsSync(paths.appTsConfig)) { @@ -53,6 +58,75 @@ function verifyTypeScriptSetup() { console.error(); process.exit(1); } + + const messages = []; + let tsconfig; + try { + tsconfig = require(paths.appTsConfig); + } catch (_) { + console.error( + chalk.red.bold( + 'Could not parse', + chalk.cyan('tsconfig.json') + '.', + 'Please make sure it contains syntactically correct JSON.' + ) + ); + process.exit(1); + } + + if (tsconfig.compilerOptions == null) { + tsconfig.compilerOptions = {}; + } + + if (tsconfig.compilerOptions.isolatedModules !== true) { + tsconfig.compilerOptions.isolatedModules = true; + messages.push( + `${chalk.cyan( + 'compilerOptions.isolatedModules' + )} must be ${chalk.cyan.bold('true')}` + ); + } + if (tsconfig.compilerOptions.noEmit !== true) { + tsconfig.compilerOptions.noEmit = true; + messages.push( + `${chalk.cyan('compilerOptions.noEmit')} must be ${chalk.cyan.bold( + 'true' + )}` + ); + } + if (tsconfig.compilerOptions.jsx !== 'preserve') { + tsconfig.compilerOptions.jsx = 'preserve'; + messages.push( + `${chalk.cyan('compilerOptions.jsx')} must be ${chalk.cyan.bold( + 'preserve' + )}` + ); + } + if (tsconfig.include == null) { + tsconfig.include = ['src']; + messages.push( + `${chalk.cyan('include')} should be ${chalk.cyan.bold('src')}` + ); + } + if (tsconfig.exclude == null) { + tsconfig.exclude = ['**/__tests__/**', '**/?*(spec|test).*']; + messages.push(`${chalk.cyan('exclude')} should exclude test files`); + } + + if (messages.length > 0) { + console.warn( + chalk.bold( + 'The following changes are being made to your', + chalk.cyan('tsconfig.json'), + 'file:' + ) + ); + messages.forEach(message => { + console.warn(' - ' + message); + }); + console.warn(); + writeJson(paths.appTsConfig, tsconfig); + } } module.exports = verifyTypeScriptSetup; From f5bcfd77056ab634870b4fa07e3d0dc810723d72 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 21 Oct 2018 19:38:16 -0400 Subject: [PATCH 2/7] Check more options --- docusaurus/docs/adding-typescript.md | 8 +------- .../scripts/utils/verifyTypeScriptSetup.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docusaurus/docs/adding-typescript.md b/docusaurus/docs/adding-typescript.md index 2e0b6a3c974..5afa7f6ee4a 100644 --- a/docusaurus/docs/adding-typescript.md +++ b/docusaurus/docs/adding-typescript.md @@ -18,19 +18,13 @@ To add TypeScript to a Create React App project, follow these steps: { "compilerOptions": { "target": "es5", - "module": "esnext", - "moduleResolution": "node", "lib": ["esnext", "dom", "dom.iterable"], "allowJs": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "isolatedModules": true, - "jsx": "preserve", - "noEmit": true, "skipLibCheck": true, "strict": true - }, - "include": ["src"] + } } ``` diff --git a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js index 1da25d17090..9241b565419 100644 --- a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js +++ b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js @@ -78,6 +78,22 @@ function verifyTypeScriptSetup() { tsconfig.compilerOptions = {}; } + if (tsconfig.compilerOptions.module !== 'esnext') { + tsconfig.compilerOptions.module = 'esnext'; + messages.push( + `${chalk.cyan('compilerOptions.module')} must be ${chalk.cyan.bold( + 'esnext' + )}` + ); + } + if (tsconfig.compilerOptions.moduleResolution !== 'node') { + tsconfig.compilerOptions.moduleResolution = 'node'; + messages.push( + `${chalk.cyan( + 'compilerOptions.moduleResolution' + )} must be ${chalk.cyan.bold('node')}` + ); + } if (tsconfig.compilerOptions.isolatedModules !== true) { tsconfig.compilerOptions.isolatedModules = true; messages.push( From c27657a351e30c694d1c2a317a29a7c7058796d7 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 21 Oct 2018 21:39:23 -0400 Subject: [PATCH 3/7] Set all defaults and suggestions --- docusaurus/docs/adding-typescript.md | 17 +--- .../scripts/utils/verifyTypeScriptSetup.js | 77 +++++++++---------- 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/docusaurus/docs/adding-typescript.md b/docusaurus/docs/adding-typescript.md index 5afa7f6ee4a..51df2a8c524 100644 --- a/docusaurus/docs/adding-typescript.md +++ b/docusaurus/docs/adding-typescript.md @@ -11,22 +11,7 @@ To add TypeScript to a Create React App project, follow these steps: 1. Run `npm install --save typescript @types/react @types/react-dom @types/jest` (or `yarn add typescript @types/react @types/react-dom @types/jest`). 2. Rename the `.js` files you want to convert: use `.tsx` if they use JSX or `.ts` if not (e.g. `git mv src/index.js src/index.tsx`). - -3. Create a [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the root directory with the following content: - -```json -{ - "compilerOptions": { - "target": "es5", - "lib": ["esnext", "dom", "dom.iterable"], - "allowJs": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "skipLibCheck": true, - "strict": true - } -} -``` +3. Create a [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the root directory with `{}` in it. 4. Copy [loaders.d.ts](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/src/loaders.d.ts) from the template to your `src` directory. diff --git a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js index 9241b565419..26615100a4f 100644 --- a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js +++ b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js @@ -78,46 +78,45 @@ function verifyTypeScriptSetup() { tsconfig.compilerOptions = {}; } - if (tsconfig.compilerOptions.module !== 'esnext') { - tsconfig.compilerOptions.module = 'esnext'; - messages.push( - `${chalk.cyan('compilerOptions.module')} must be ${chalk.cyan.bold( - 'esnext' - )}` - ); - } - if (tsconfig.compilerOptions.moduleResolution !== 'node') { - tsconfig.compilerOptions.moduleResolution = 'node'; - messages.push( - `${chalk.cyan( - 'compilerOptions.moduleResolution' - )} must be ${chalk.cyan.bold('node')}` - ); - } - if (tsconfig.compilerOptions.isolatedModules !== true) { - tsconfig.compilerOptions.isolatedModules = true; - messages.push( - `${chalk.cyan( - 'compilerOptions.isolatedModules' - )} must be ${chalk.cyan.bold('true')}` - ); - } - if (tsconfig.compilerOptions.noEmit !== true) { - tsconfig.compilerOptions.noEmit = true; - messages.push( - `${chalk.cyan('compilerOptions.noEmit')} must be ${chalk.cyan.bold( - 'true' - )}` - ); - } - if (tsconfig.compilerOptions.jsx !== 'preserve') { - tsconfig.compilerOptions.jsx = 'preserve'; - messages.push( - `${chalk.cyan('compilerOptions.jsx')} must be ${chalk.cyan.bold( - 'preserve' - )}` - ); + const compilerOptions = { + target: { suggested: 'es5' }, + allowJs: { suggested: true }, + skipLibCheck: { suggested: true }, + module: { value: 'esnext', reason: 'for import() and import/export' }, + moduleResolution: { value: 'node', reason: 'to match webpack resolution' }, + isolatedModules: { value: true, reason: 'implementation limitation' }, + noEmit: { value: true }, + jsx: { value: 'preserve', reason: 'JSX is compiled by Babel' }, + esModuleInterop: { value: true, reason: 'Babel compatibility' }, + allowSyntheticDefaultImports: { + value: true, + reason: 'Babel compatibility', + }, + strict: { suggested: true }, + }; + + for (const option of Object.keys(compilerOptions)) { + const { value, suggested, reason } = compilerOptions[option]; + if (suggested != null) { + if (tsconfig.compilerOptions[option] === undefined) { + tsconfig.compilerOptions[option] = suggested; + messages.push( + `${chalk.cyan('compilerOptions.' + option)} to be ${chalk.bold( + 'suggested' + )} value: ${chalk.cyan.bold(suggested)} (this can be changed)` + ); + } + } else if (tsconfig.compilerOptions[option] !== value) { + tsconfig.compilerOptions[option] = value; + messages.push( + `${chalk.cyan('compilerOptions.' + option)} ${chalk.bold( + 'must' + )} be ${chalk.cyan.bold(value)}` + + (reason != null ? ` (${reason})` : '') + ); + } } + if (tsconfig.include == null) { tsconfig.include = ['src']; messages.push( From dce56a82f9bc875321d45f0b7da3557092f7525e Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 21 Oct 2018 21:42:30 -0400 Subject: [PATCH 4/7] Update docs --- docusaurus/docs/adding-typescript.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docusaurus/docs/adding-typescript.md b/docusaurus/docs/adding-typescript.md index 51df2a8c524..30fc453006a 100644 --- a/docusaurus/docs/adding-typescript.md +++ b/docusaurus/docs/adding-typescript.md @@ -12,8 +12,9 @@ To add TypeScript to a Create React App project, follow these steps: 1. Run `npm install --save typescript @types/react @types/react-dom @types/jest` (or `yarn add typescript @types/react @types/react-dom @types/jest`). 2. Rename the `.js` files you want to convert: use `.tsx` if they use JSX or `.ts` if not (e.g. `git mv src/index.js src/index.tsx`). 3. Create a [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the root directory with `{}` in it. +4. Restart your development server (if applicable). -4. Copy [loaders.d.ts](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/src/loaders.d.ts) from the template to your `src` directory. +5. Copy [loaders.d.ts](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/src/loaders.d.ts) from the template to your `src` directory. Type errors will show up in the same console as the build one. From 63d36f3b940fd16ad1c4c942481db0aac5ed2ecb Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Sun, 21 Oct 2018 22:21:22 -0400 Subject: [PATCH 5/7] Update doc notes --- docusaurus/docs/adding-typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/adding-typescript.md b/docusaurus/docs/adding-typescript.md index 30fc453006a..34edbd07007 100644 --- a/docusaurus/docs/adding-typescript.md +++ b/docusaurus/docs/adding-typescript.md @@ -12,7 +12,7 @@ To add TypeScript to a Create React App project, follow these steps: 1. Run `npm install --save typescript @types/react @types/react-dom @types/jest` (or `yarn add typescript @types/react @types/react-dom @types/jest`). 2. Rename the `.js` files you want to convert: use `.tsx` if they use JSX or `.ts` if not (e.g. `git mv src/index.js src/index.tsx`). 3. Create a [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the root directory with `{}` in it. -4. Restart your development server (if applicable). +4. Restart your development server (if applicable). This will set sensible defaults and the required values in your [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). 5. Copy [loaders.d.ts](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/src/loaders.d.ts) from the template to your `src` directory. From 1be66903698ae45c8939051f3a60f4ce66777b16 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Mon, 22 Oct 2018 00:10:17 -0400 Subject: [PATCH 6/7] Automatically copy react app declared types to project on start --- .../src/loaders.d.ts => config/react-app.d.ts} | 4 ++++ packages/react-scripts/scripts/test.js | 2 ++ .../scripts/utils/verifyTypeScriptSetup.js | 17 +++++++++++++++++ 3 files changed, 23 insertions(+) rename packages/react-scripts/{template/src/loaders.d.ts => config/react-app.d.ts} (83%) diff --git a/packages/react-scripts/template/src/loaders.d.ts b/packages/react-scripts/config/react-app.d.ts similarity index 83% rename from packages/react-scripts/template/src/loaders.d.ts rename to packages/react-scripts/config/react-app.d.ts index a683144ed66..5994114ffda 100644 --- a/packages/react-scripts/template/src/loaders.d.ts +++ b/packages/react-scripts/config/react-app.d.ts @@ -1,3 +1,7 @@ +// @remove-file-on-eject +// Do not edit this file. It's replaced every time you launch a toolbox action. +// If you need to add additional declarations, please do so in a new file. + declare module '*.json' { const value: any; export default value; diff --git a/packages/react-scripts/scripts/test.js b/packages/react-scripts/scripts/test.js index 9102960f2cd..ac07e4792af 100644 --- a/packages/react-scripts/scripts/test.js +++ b/packages/react-scripts/scripts/test.js @@ -28,6 +28,8 @@ const verifyPackageTree = require('./utils/verifyPackageTree'); if (process.env.SKIP_PREFLIGHT_CHECK !== 'true') { verifyPackageTree(); } +const verifyTypeScriptSetup = require('./utils/verifyTypeScriptSetup'); +verifyTypeScriptSetup(); // @remove-on-eject-end const jest = require('jest'); diff --git a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js index 26615100a4f..1698ef5ecbd 100644 --- a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js +++ b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js @@ -11,6 +11,7 @@ const chalk = require('chalk'); const fs = require('fs'); const resolve = require('resolve'); +const path = require('path'); const paths = require('../../config/paths'); const os = require('os'); @@ -142,6 +143,22 @@ function verifyTypeScriptSetup() { console.warn(); writeJson(paths.appTsConfig, tsconfig); } + + // Copy type declarations associated with this version of `react-scripts` + const declaredTypes = path.resolve( + __dirname, + '..', + '..', + 'config', + 'react-app.d.ts' + ); + const declaredTypesContent = fs + .readFileSync(declaredTypes, 'utf8') + .replace(/\/\/ @remove-file-on-eject\r?\n/, ''); + fs.writeFileSync( + path.resolve(paths.appSrc, 'react-app.d.ts'), + declaredTypesContent + ); } module.exports = verifyTypeScriptSetup; From 0ea035636e6b4c87a68fdaf45ca38d084532b50b Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Mon, 22 Oct 2018 00:42:10 -0400 Subject: [PATCH 7/7] Remove note about loaders.d.ts --- docusaurus/docs/adding-typescript.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docusaurus/docs/adding-typescript.md b/docusaurus/docs/adding-typescript.md index 34edbd07007..bf99e677b05 100644 --- a/docusaurus/docs/adding-typescript.md +++ b/docusaurus/docs/adding-typescript.md @@ -14,8 +14,6 @@ To add TypeScript to a Create React App project, follow these steps: 3. Create a [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the root directory with `{}` in it. 4. Restart your development server (if applicable). This will set sensible defaults and the required values in your [`tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). -5. Copy [loaders.d.ts](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/src/loaders.d.ts) from the template to your `src` directory. - Type errors will show up in the same console as the build one. We recommend using [VSCode](https://code.visualstudio.com/) for a better integrated experience.