From f739945c20614b589d6a566bffc0aa10eb9e7c9e Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 2 Nov 2022 15:06:47 -0700 Subject: [PATCH] Use TypeScript by default for new applications (#35165) Summary: This change moves the default new application template in OSS from Flow to TypeScript. This better aligns with the communities usage, and aligns to the great work that has been happening for TS codegen and built-in types. This used [`react-native-community/react-native-template-typescript`](https://github.com/react-native-community/react-native-template-typescript) as a main reference, maintained by radko93. A few things are different: 1. Updated `types/*` devDependencies to match bumped libraries (e.g. Jest 26 to 20). 2. Removed `types/react-native` 3. Removed explicit `moduleFileExtensions` to Jest config in package.json (TS and TSX and added by default in current versions) 4. Removed overrides to eslint config to disable `no-shadow` and `no-undef`, since this was fixed in the underlying eslint config with https://github.com/facebook/react-native/pull/32644 and https://github.com/facebook/react-native/pull/32655 5. Re-translated `App.js` to be a direct translation (e.g. still a raw function instead of React.FC which is sometimes discouraged) 6. Aligns completely to `tsconfig/react-native` maintained configuration (We no longer have the opinionated override of `skipLibCheck`). The important settings are that `strict` is enabled for, but `allowJS` is also enabled to let users import JS modules without anything unexpected. `esModuleInterop` is enabled, which is needed for consistency with Babel import transformations used by Metro. Consistent with our [current documentation](https://reactnative.dev/docs/typescript) built against the community template, `tsc` will typecheck your code without emitting(building) anything. [Documentation](https://reactnative.dev/docs/typescript) will need to be updated as a followup. Changelog: [General][Changed] - Use TypeScript by default for new applications Pull Request resolved: https://github.com/facebook/react-native/pull/35165 Test Plan: Added usage of `tsc` and `jest` when validating a newly built app. Passes in CircleCI `test_js` job. This also meant removing some cases of copying packages into the users app to pull in the root Metro config (we seem to be able to use the template Metro config consistent with what real apps would get). Reviewed By: cortinico Differential Revision: D40911951 Pulled By: NickGerleman fbshipit-source-id: 08d4624bc08163c7dc1272f605bc3a8e9a89173b --- scripts/run-ci-e2e-tests.js | 32 +++++----- template/{App.js => App.tsx} | 14 ++--- .../__tests__/{App-test.js => App-test.tsx} | 0 template/_buckconfig | 6 -- template/_eslintrc.js | 2 + template/_flowconfig | 63 ------------------- template/package.json | 13 +++- template/tsconfig.json | 3 + 8 files changed, 35 insertions(+), 98 deletions(-) rename template/{App.js => App.tsx} (92%) rename template/__tests__/{App-test.js => App-test.tsx} (100%) delete mode 100644 template/_buckconfig delete mode 100644 template/_flowconfig create mode 100644 template/tsconfig.json diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index 1c013ba073537c..cdff750f3192b9 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -89,19 +89,9 @@ try { exec(`rsync -a ${ROOT}/template ${REACT_NATIVE_TEMP_DIR}`); cd(REACT_NATIVE_APP_DIR); - const METRO_CONFIG = path.join(ROOT, 'metro.config.js'); - const RN_GET_POLYFILLS = path.join(ROOT, 'rn-get-polyfills.js'); - const RN_POLYFILLS_PATH = 'packages/polyfills/'; - exec(`mkdir -p ${RN_POLYFILLS_PATH}`); - - cp(METRO_CONFIG, '.'); - cp(RN_GET_POLYFILLS, '.'); - exec( - `rsync -a ${ROOT}/${RN_POLYFILLS_PATH} ${REACT_NATIVE_APP_DIR}/${RN_POLYFILLS_PATH}`, - ); - mv('_flowconfig', '.flowconfig'); - mv('_watchmanconfig', '.watchmanconfig'); mv('_bundle', '.bundle'); + mv('_eslintrc.js', '.eslintrc.js'); + mv('_watchmanconfig', '.watchmanconfig'); describe('Install React Native package'); exec(`npm install ${REACT_NATIVE_PACKAGE}`); @@ -267,6 +257,7 @@ try { exitCode = 1; throw Error(exitCode); } + describe('Test: Verify packager can generate an iOS bundle'); if ( exec( @@ -277,12 +268,17 @@ try { exitCode = 1; throw Error(exitCode); } - describe('Test: Flow check'); - // The resolve package included a test for a malformed package.json (see https://github.com/browserify/resolve/issues/89) - // that is failing the flow check. We're removing it. - rm('-rf', './node_modules/resolve/test/resolver/malformed_package_json'); - if (exec(`${ROOT}/node_modules/.bin/flow check`).code) { - echo('Flow check failed.'); + + describe('Test: TypeScript typechecking'); + if (exec('yarn tsc').code) { + echo('Typechecking errors were found'); + exitCode = 1; + throw Error(exitCode); + } + + describe('Test: Jest tests'); + if (exec('yarn test').code) { + echo('Jest tests failed'); exitCode = 1; throw Error(exitCode); } diff --git a/template/App.js b/template/App.tsx similarity index 92% rename from template/App.js rename to template/App.tsx index ba7b59897f496e..71991406fe1fe9 100644 --- a/template/App.js +++ b/template/App.tsx @@ -3,11 +3,10 @@ * https://github.com/facebook/react-native * * @format - * @flow strict-local */ import React from 'react'; -import type {Node} from 'react'; +import type {PropsWithChildren} from 'react'; import { SafeAreaView, ScrollView, @@ -26,12 +25,11 @@ import { ReloadInstructions, } from 'react-native/Libraries/NewAppScreen'; -type SectionProps = { - title: string, - children: Node, -}; +type SectionProps = PropsWithChildren<{ + title: string; +}>; -function Section({children, title}: SectionProps): Node { +function Section({children, title}: SectionProps): JSX.Element { const isDarkMode = useColorScheme() === 'dark'; return ( @@ -57,7 +55,7 @@ function Section({children, title}: SectionProps): Node { ); } -function App(): Node { +function App(): JSX.Element { const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { diff --git a/template/__tests__/App-test.js b/template/__tests__/App-test.tsx similarity index 100% rename from template/__tests__/App-test.js rename to template/__tests__/App-test.tsx diff --git a/template/_buckconfig b/template/_buckconfig deleted file mode 100644 index 934256cb29d4a3..00000000000000 --- a/template/_buckconfig +++ /dev/null @@ -1,6 +0,0 @@ - -[android] - target = Google Inc.:Google APIs:23 - -[maven_repositories] - central = https://repo1.maven.org/maven2 diff --git a/template/_eslintrc.js b/template/_eslintrc.js index 40c6dcd05f3100..189699723fd268 100644 --- a/template/_eslintrc.js +++ b/template/_eslintrc.js @@ -1,4 +1,6 @@ module.exports = { root: true, extends: '@react-native-community', + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], }; diff --git a/template/_flowconfig b/template/_flowconfig deleted file mode 100644 index b929e039dc850d..00000000000000 --- a/template/_flowconfig +++ /dev/null @@ -1,63 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore polyfills -node_modules/react-native/Libraries/polyfills/.* - -; Flow doesn't support platforms -.*/Libraries/Utilities/LoadingView.js - -.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ - -[untyped] -.*/node_modules/@react-native-community/cli/.*/.* - -[include] - -[libs] -node_modules/react-native/interface.js -node_modules/react-native/flow/ - -[options] -emoji=true - -exact_by_default=true - -format.bracket_spacing=false - -module.file_ext=.js -module.file_ext=.json -module.file_ext=.ios.js - -munge_underscores=true - -module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' -module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FlowFixMeProps -suppress_type=$FlowFixMeState - -[lints] -sketchy-null-number=warn -sketchy-null-mixed=warn -sketchy-number=warn -untyped-type-import=warn -nonstrict-import=warn -deprecated-type=warn -unsafe-getters-setters=warn -unnecessary-invariant=warn - -[strict] -deprecated-type -nonstrict-import -sketchy-null -unclear-type -unsafe-getters-setters -untyped-import -untyped-type-import - -[version] -^0.191.0 diff --git a/template/package.json b/template/package.json index af4a7228d099ca..b70769d0759293 100644 --- a/template/package.json +++ b/template/package.json @@ -5,9 +5,9 @@ "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", + "lint": "eslint .", "start": "react-native start", - "test": "jest", - "lint": "eslint ." + "test": "jest" }, "dependencies": { "react": "18.2.0", @@ -17,11 +17,18 @@ "@babel/core": "^7.12.9", "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^3.0.0", + "@tsconfig/react-native": "^2.0.2", + "@types/jest": "^29.2.1", + "@types/react": "^18.0.24", + "@types/react-test-renderer": "^18.0.0", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", "babel-jest": "^29.2.1", "eslint": "^8.19.0", "jest": "^29.2.1", "metro-react-native-babel-preset": "0.73.3", - "react-test-renderer": "18.2.0" + "react-test-renderer": "18.2.0", + "typescript": "^4.8.3" }, "jest": { "preset": "react-native" diff --git a/template/tsconfig.json b/template/tsconfig.json new file mode 100644 index 00000000000000..45a6c707223871 --- /dev/null +++ b/template/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/react-native/tsconfig.json" +}