diff --git a/ExampleProject/.buckconfig b/.buckconfig similarity index 100% rename from ExampleProject/.buckconfig rename to .buckconfig diff --git a/ExampleProject/.gitignore b/.gitignore similarity index 96% rename from ExampleProject/.gitignore rename to .gitignore index 142157d..285e5ae 100644 --- a/ExampleProject/.gitignore +++ b/.gitignore @@ -56,6 +56,9 @@ buck-out/ # lib/ +# Bundle artifact +*.jsbundle + # Jest # .jest/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5b24ad6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - node + +cache: yarn + +script: + - yarn test \ No newline at end of file diff --git a/ExampleProject/.watchmanconfig b/.watchmanconfig similarity index 100% rename from ExampleProject/.watchmanconfig rename to .watchmanconfig diff --git a/ExampleProject/.babelrc b/ExampleProject/.babelrc deleted file mode 100644 index a9ce136..0000000 --- a/ExampleProject/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["react-native"] -} diff --git a/ExampleProject/.flowconfig b/ExampleProject/.flowconfig deleted file mode 100644 index 10cb8d5..0000000 --- a/ExampleProject/.flowconfig +++ /dev/null @@ -1,54 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore "BUCK" generated dirs -/\.buckd/ - -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js - -; Ignore polyfills -.*/Libraries/polyfills/.* - -; Ignore metro -.*/node_modules/metro/.* - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js -node_modules/react-native/flow/ -node_modules/react-native/flow-github/ - -[options] -emoji=true - -module.system=haste - -munge_underscores=true - -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\)$' -> 'RelativeImageStub' - -module.file_ext=.js -module.file_ext=.jsx -module.file_ext=.json -module.file_ext=.native.js - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FlowFixMeProps -suppress_type=$FlowFixMeState - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy -suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError - -[version] -^0.65.0 diff --git a/ExampleProject/.gitattributes b/ExampleProject/.gitattributes deleted file mode 100644 index d42ff18..0000000 --- a/ExampleProject/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.pbxproj -text diff --git a/ExampleProject/android/app/proguard-rules.pro b/ExampleProject/android/app/proguard-rules.pro deleted file mode 100644 index 6e8516c..0000000 --- a/ExampleProject/android/app/proguard-rules.pro +++ /dev/null @@ -1,70 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). --dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. -# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. --dontwarn android.text.StaticLayout - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** diff --git a/ExampleProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ExampleProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bc..0000000 Binary files a/ExampleProject/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/ExampleProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ExampleProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0c..0000000 Binary files a/ExampleProject/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/ExampleProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ExampleProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0..0000000 Binary files a/ExampleProject/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/ExampleProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ExampleProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72c..0000000 Binary files a/ExampleProject/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/ExampleProject/android/gradle/wrapper/gradle-wrapper.jar b/ExampleProject/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index b5166da..0000000 Binary files a/ExampleProject/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/ExampleProject/ios/ExampleProject/AppDelegate.h b/ExampleProject/ios/ExampleProject/AppDelegate.h deleted file mode 100644 index a9654d5..0000000 --- a/ExampleProject/ios/ExampleProject/AppDelegate.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; - -@end diff --git a/ExampleProject/package-lock.json b/ExampleProject/package-lock.json deleted file mode 100644 index 49c8d3c..0000000 --- a/ExampleProject/package-lock.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "ExampleProject", - "version": "0.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/jest": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-22.2.2.tgz", - "integrity": "sha512-Dt7aifQmvMPTLVimzvfQ99qUn4zeSDCQarFNV4otfDLYu0RFdSRBnqSLgksoAnsRL88xJ/UBKbd66iP2XIab0w==", - "dev": true - }, - "@types/react": { - "version": "16.0.41", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.0.41.tgz", - "integrity": "sha512-hbAKPclom+NzM/iqB9JmP7UfWl0j/xsOIzWCB8iIJ7Dq0BlY80IeulgHwod2EOYILD5hc/DJAJvMFKfczdWBsQ==", - "dev": true - }, - "@types/react-test-renderer": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-16.0.1.tgz", - "integrity": "sha512-kmNh8g67Ck/y/vp6KX+4JTJXiTGLZBylNhu+R7sm7zcvsrnIGVO6J1zew5inVg428j9f8yHpl68RcYOZXVborQ==", - "dev": true, - "requires": { - "@types/react": "16.0.41" - } - } - } -} diff --git a/ExampleProject/package.json b/ExampleProject/package.json deleted file mode 100644 index f6b3974..0000000 --- a/ExampleProject/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "ExampleProject", - "version": "0.0.1", - "private": true, - "scripts": { - "start": "node node_modules/react-native/local-cli/cli.js start", - "test": "jest" - }, - "dependencies": { - "react": "^16.3.0-alpha.1", - "react-native": "0.54.3" - }, - "devDependencies": { - "@types/jest": "^22.2.2", - "@types/react": "^16.0.41", - "@types/react-native": "^0.52.19", - "@types/react-test-renderer": "^16.0.1", - "babel-jest": "22.4.3", - "babel-preset-react-native": "4.0.0", - "jest": "22.4.3", - "react-addons-test-utils": "^15.6.2", - "react-native-mock": "^0.3.1", - "react-native-typescript-transformer": "^1.2.3", - "react-test-renderer": "^16.3.0-alpha.1", - "ts-jest": "^22.4.2", - "typescript": "^2.8.1" - }, - "jest": { - "preset": "react-native", - "moduleFileExtensions": [ - "ts", - "tsx", - "js" - ], - "transform": { - "^.+\\.(js)$": "/node_modules/babel-jest", - "\\.(ts|tsx)$": "/node_modules/ts-jest/preprocessor.js" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", - "testPathIgnorePatterns": [ - "\\.snap$", - "/node_modules/", - "/lib/" - ], - "cacheDirectory": ".jest/cache" - } -} diff --git a/LICENSE b/LICENSE index 4b1ad51..527f8f1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ - MIT License +MIT License - Copyright (c) Microsoft Corporation. All rights reserved. +Copyright (c) Microsoft Corporation. All rights reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE diff --git a/README.md b/README.md index a4d9d67..f7acd2f 100644 --- a/README.md +++ b/README.md @@ -1,299 +1,68 @@ # TypeScript React Native Starter -## Prerequisites - -Because you might be developing on one of several different platforms, targeting several different types of devices, basic setup can be involved. -You should first ensure that you can run a plain React Native app without TypeScript. -Follow [the instructions on the React Native website to get started](https://facebook.github.io/react-native/docs/getting-started.html). -When you've managed to deploy to a device or emulator, you'll be ready to start a TypeScript React Native app. - -You will also need [Node.js](https://nodejs.org/en/), [NPM](https://www.npmjs.com), and [Yarn](https://yarnpkg.com/lang/en). - -## Initializing - -Once you've tried scaffolding out an ordinary React Native project, you'll be ready to start adding TypeScript. -Let's go ahead and do that. - -```sh -react-native init MyAwesomeProject -cd MyAwesomeProject -``` +[![Greenkeeper badge](https://badges.greenkeeper.io/Li-Victor/TypeScript-React-Native-Starter.svg)](https://greenkeeper.io/) -## Adding TypeScript +Up to date Typescript React Native Starter project. Based on [React Native blog post](https://facebook.github.io/react-native/blog/2018/05/07/using-typescript-with-react-native) and [repository](https://github.com/Microsoft/TypeScript-React-Native-Starter). -The next step is to add TypeScript to your project. -The following commands will: +Android | iOS +|:--:|:--:| + | -* add TypeScript to your project -* add [React Native TypeScript Transformer](https://github.com/ds300/react-native-typescript-transformer) to your project -* initialize an empty TypeScript config file, which we'll configure next -* add an empty React Native TypeScript Transformer config file, which we'll configure next -* Adds [typings](https://github.com/DefinitelyTyped/DefinitelyTyped) for React and React Native - -Okay let's go ahead and run these. - -```sh -yarn add --dev typescript -yarn add --dev react-native-typescript-transformer -yarn tsc --init --pretty --jsx react -touch rn-cli.config.js -yarn add --dev @types/react @types/react-native -``` +## Prerequisites +You will need [Node.js](https://nodejs.org/en/), [NPM](https://www.npmjs.com), and [Yarn](https://yarnpkg.com/lang/en). -The `tsconfig.json` file contains all the settings for the TypeScript compile. -The defaults created by the command above are mostly fine, but open the file and uncomment the following line: +## Renaming Project -```js -{ - ... - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - ... -} -``` +The application is called ExampleProject. If you to rename the project, use [react-native-rename](https://github.com/junedomingo/react-native-rename). -The `rn-cli.config.js` contains the settings for the React Native TypeScript Transformer. -Open it and add the following: +### Installation -```js -module.exports = { - getTransformModulePath() { - return require.resolve("react-native-typescript-transformer"); - }, - getSourceExts() { - return ["ts", "tsx"]; - } -}; ``` - -## Migrating to TypeScript - -Rename the generated `App.js` and `__tests__/App.js` files to `App.tsx`. `index.js` needs to use the `.js` extension. -All new files should use the `.tsx` extension (or `.ts` if the file doesn't contain any JSX). - -If you try to run the app now, you'll get an error like `object prototype may only be an object or null`. -This is caused by a failure to import the default export from React as well as a named export on the same line. -Open `App.tsx` and modify the import at the top of the file: - -```diff --import React, { Component } from 'react'; -+import React from 'react' -+import { Component } from 'react'; +yarn global add react-native-rename +or +npm install react-native-rename -g ``` -Some of this has to do with differences in how Babel and TypeScript interoperate with CommonJS modules. -In the future, the two will stabilize on the same behavior. - -At this point, you should be able to run the React Native app. - -## Adding TypeScript Testing Infrastructure - -Since we're using [Jest](https://github.com/facebook/jest), we'll want to add [ts-jest](https://www.npmjs.com/package/ts-jest) to our devDependencies. +Switch to new branch first +> better to have back-up ```sh -yarn add --dev ts-jest +git checkout -b rename-app ``` -Then, we'll open up our `package.json` and replace the `jest` field with the following: +#### Usage -```json -"jest": { - "preset": "react-native", - "moduleFileExtensions": [ - "ts", - "tsx", - "js" - ], - "transform": { - "^.+\\.(js)$": "/node_modules/babel-jest", - "\\.(ts|tsx)$": "/node_modules/ts-jest/preprocessor.js" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", - "testPathIgnorePatterns": [ - "\\.snap$", - "/node_modules/" - ], - "cacheDirectory": ".jest/cache" -} ``` - -This will configure Jest to run `.ts` and `.tsx` files with `ts-jest`. - -## Installing Type Declaration Dependencies - -To get the best experience in TypeScript, we want the type-checker to understand the shape and API of our dependencies. -Some libraries will publish their packages with `.d.ts` files (also called "typed declaration" or "type definition" files) which can describe the shape of the underlying JavaScript. -For other libraries, we'll need to explicitly install the appropriate package in the `@types/` npm scope. - -For example, here we'll need types for Jest, React, and React Native, and React Test Renderer. - -```ts -yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer +react-native-rename +watchman watch-del-all +npm start --reset-cache ``` -We saved these declaration file packages to our _dev_ dependencies because we're not publishing this package as a library to npm. -If we were, we might have to add some of them as regular dependencies. - -You can read more [here about getting `.d.ts` files](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html). - -## Ignoring More Files - -For your source control, you'll want to start ignoring the `.jest` folder. -If you're using git, we can just add entries to our `.gitignore` file. - -```config -# Jest -# -.jest/ +> With custom Bundle Identifier (Android only. For iOS, please use Xcode) ``` - -As a checkpoint, consider committing your files into version control. - -```sh -git init -git add .gitignore # import to do this first, to ignore our files -git add . -git commit -am "Initial commit." +react-native-rename -b +watchman watch-del-all +npm start --reset-cache ``` -## Adding a Component - -We can now add a component to our app. -Let's go ahead and create a `Hello.tsx` component. -Create a `components` directory and add the following example. - -```ts -// components/Hello.tsx -import React from "react" -import { Button, StyleSheet, Text, View } from "react-native" - -export interface Props { - name: string - enthusiasmLevel?: number - onIncrement?: () => void - onDecrement?: () => void -} - -interface State { - enthusiasmLevel: number -} - -export class Hello extends React.Component { - constructor(props: Props) { - super(props) - - if ((props.enthusiasmLevel || 0) <= 0) { - throw new Error("You could be a little more enthusiastic. :D") - } - - this.state = { - enthusiasmLevel: props.enthusiasmLevel || 1 - } - } - - onIncrement = () => this.setState({ enthusiasmLevel: this.state.enthusiasmLevel + 1 }); - onDecrement = () => this.setState({ enthusiasmLevel: this.state.enthusiasmLevel - 1 }); - getExclamationMarks = (numChars: number) => Array(numChars + 1).join("!") - - render() { - return ( - - - Hello {this.props.name + this.getExclamationMarks(this.state.enthusiasmLevel)} - - - - -