Convert Figma logo to code with AI

microsoft logoTypeScript-React-Native-Starter

A starter template for TypeScript and React Native with a detailed README describing how to use the two together.

1,910
210
1,910
43

Top Related Projects

A framework for building native applications using React

👾 Clean and minimalist React Native template for a quick start with TypeScript.

17,543

Infinite Red's battle-tested React Native project boilerplate, along with a CLI, component/model generators, and more!

33,519

An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.

Material Design for React Native (Android & iOS)

A complete native navigation solution for React Native

Quick Overview

The Microsoft/TypeScript-React-Native-Starter is a template repository for building React Native applications using TypeScript. It provides a pre-configured environment with essential tools and best practices, allowing developers to quickly start building cross-platform mobile apps with type safety and modern JavaScript features.

Pros

  • Combines the power of React Native with TypeScript's static typing
  • Includes pre-configured testing setup with Jest
  • Provides a well-structured project layout following best practices
  • Includes ESLint and Prettier for code quality and consistency

Cons

  • May have a steeper learning curve for developers new to TypeScript
  • Requires more initial setup compared to plain JavaScript React Native projects
  • Some third-party libraries may not have TypeScript definitions readily available
  • Potential performance overhead due to TypeScript compilation

Code Examples

  1. Defining a typed component prop:
interface GreetingProps {
  name: string;
  age?: number;
}

const Greeting: React.FC<GreetingProps> = ({ name, age }) => {
  return (
    <Text>
      Hello, {name}! {age && `You are ${age} years old.`}
    </Text>
  );
};
  1. Using typed state with React hooks:
const [count, setCount] = useState<number>(0);

const incrementCount = () => {
  setCount((prevCount) => prevCount + 1);
};
  1. Typed API call using async/await:
interface User {
  id: number;
  name: string;
  email: string;
}

const fetchUser = async (id: number): Promise<User> => {
  const response = await fetch(`https://api.example.com/users/${id}`);
  if (!response.ok) {
    throw new Error('Failed to fetch user');
  }
  return response.json();
};

Getting Started

  1. Clone the repository:

    git clone https://github.com/microsoft/TypeScript-React-Native-Starter.git
    
  2. Install dependencies:

    cd TypeScript-React-Native-Starter
    npm install
    
  3. Start the Metro bundler:

    npx react-native start
    
  4. Run the app on iOS or Android:

    npx react-native run-ios
    # or
    npx react-native run-android
    

Competitor Comparisons

A framework for building native applications using React

Pros of React Native

  • Larger community and ecosystem, with more third-party libraries and resources
  • More comprehensive documentation and official tutorials
  • Actively maintained by Facebook with frequent updates and improvements

Cons of React Native

  • Steeper learning curve for beginners, especially those new to React
  • Potentially more complex setup and configuration process
  • May require additional tools or libraries for TypeScript integration

Code Comparison

TypeScript-React-Native-Starter:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App: React.FC = () => {
  return (
    <View style={styles.container}>
      <Text>Welcome to React Native with TypeScript!</Text>
    </View>
  );
};

React Native:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text>Welcome to React Native!</Text>
    </View>
  );
};

The main difference is that TypeScript-React-Native-Starter uses TypeScript by default, providing type annotations and improved developer experience, while React Native uses JavaScript and requires additional setup for TypeScript support.

👾 Clean and minimalist React Native template for a quick start with TypeScript.

Pros of react-native-template-typescript

  • More actively maintained with frequent updates
  • Simpler setup process, requiring fewer manual configurations
  • Better integration with the latest React Native features and best practices

Cons of react-native-template-typescript

  • Less comprehensive documentation compared to TypeScript-React-Native-Starter
  • Fewer pre-configured tools and libraries out of the box
  • May require additional setup for more advanced TypeScript configurations

Code Comparison

TypeScript-React-Native-Starter:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>Open up App.tsx to start working on your app!</Text>
      </View>
    );
  }
}

react-native-template-typescript:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
    </View>
  );
};

export default App;

The main difference in the code examples is that TypeScript-React-Native-Starter uses a class component, while react-native-template-typescript uses a functional component with hooks, reflecting more modern React practices.

17,543

Infinite Red's battle-tested React Native project boilerplate, along with a CLI, component/model generators, and more!

Pros of Ignite

  • More comprehensive boilerplate with additional features and integrations
  • Includes a CLI tool for generating components, screens, and other project elements
  • Offers a selection of pre-configured boilerplates for different project needs

Cons of Ignite

  • Steeper learning curve due to additional complexity and opinionated structure
  • May include unnecessary features for simpler projects
  • Requires more setup and configuration compared to a minimal starter

Code Comparison

TypeScript-React-Native-Starter:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
    </View>
  );
}

Ignite:

import React from 'react'
import { AppNavigator } from './navigators'
import { RootStore, RootStoreProvider, setupRootStore } from './models'
import { ErrorBoundary } from './screens/error/error-boundary'

export const App: React.FunctionComponent<{}> = () => {
  const [rootStore, setRootStore] = React.useState<RootStore | undefined>(undefined)
  // ... (additional setup code)
}

The TypeScript-React-Native-Starter provides a minimal setup, while Ignite includes more advanced features like navigation, state management, and error boundaries out of the box.

33,519

An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.

Pros of Expo

  • Easier setup and development process, especially for beginners
  • Provides a comprehensive set of pre-built components and APIs
  • Offers over-the-air updates and simplified deployment

Cons of Expo

  • Limited access to native modules and custom native code
  • Larger app size due to included libraries and dependencies
  • Potential performance limitations for complex applications

Code Comparison

TypeScript-React-Native-Starter:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App: React.FC = () => {
  return (
    <View style={styles.container}>
      <Text>Welcome to React Native with TypeScript!</Text>
    </View>
  );
};

Expo:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Welcome to Expo!</Text>
    </View>
  );
}

The main difference in the code examples is that TypeScript-React-Native-Starter uses TypeScript and defines the component as a functional component with explicit typing, while Expo uses JavaScript and exports the component as the default export.

Material Design for React Native (Android & iOS)

Pros of React Native Paper

  • Comprehensive UI component library specifically designed for React Native
  • Material Design implementation, providing a consistent and modern look
  • Active development and community support

Cons of React Native Paper

  • Larger bundle size due to the inclusion of many components
  • May require additional configuration for custom theming
  • Potential performance impact for complex applications

Code Comparison

TypeScript-React-Native-Starter:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const MyComponent = () => (
  <View style={styles.container}>
    <Text>Hello, TypeScript React Native!</Text>
  </View>
);

React Native Paper:

import React from 'react';
import { View } from 'react-native';
import { Button, Text } from 'react-native-paper';

const MyComponent = () => (
  <View>
    <Text>Hello, React Native Paper!</Text>
    <Button mode="contained" onPress={() => console.log('Pressed')}>
      Press me
    </Button>
  </View>
);

The TypeScript-React-Native-Starter repository focuses on providing a TypeScript-based starting point for React Native projects, while React Native Paper offers a rich set of pre-built UI components following Material Design principles. The code comparison illustrates the difference in component usage and styling approach between the two projects.

A complete native navigation solution for React Native

Pros of react-native-navigation

  • More comprehensive navigation solution with advanced features like deep linking and custom animations
  • Better performance due to native implementation, especially for complex navigation structures
  • Larger community and more frequent updates

Cons of react-native-navigation

  • Steeper learning curve and more complex setup compared to simpler navigation solutions
  • Potential compatibility issues with certain third-party libraries
  • Requires additional native code integration, which may be challenging for some developers

Code Comparison

TypeScript-React-Native-Starter:

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

react-native-navigation:

import { Navigation } from 'react-native-navigation';

Navigation.registerComponent('Home', () => HomeScreen);
Navigation.registerComponent('Details', () => DetailsScreen);

Navigation.setRoot({
  root: {
    stack: {
      children: [
        { component: { name: 'Home' } },
      ],
    },
  },
});

The TypeScript-React-Native-Starter uses React Navigation, which is simpler to set up and integrate, while react-native-navigation offers more control and native performance at the cost of increased complexity.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

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. 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, NPM, and Yarn.

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.

react-native init MyAwesomeProject
cd MyAwesomeProject

Adding TypeScript

The next step is to add TypeScript to your project. The following commands will:

  • add TypeScript to your project
  • add 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 for React and React Native

Okay let's go ahead and run these.

yarn add --dev typescript
yarn add --dev react-native-typescript-transformer
yarn tsc --init --pretty --jsx react-native
touch rn-cli.config.js
yarn add --dev @types/react @types/react-native

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:

{
  ...
  // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
  ...
}

The rn-cli.config.js contains the settings for the React Native TypeScript Transformer. Open it and add the following:

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:

-import React, { Component } from 'react'
+import React from 'react'
+import { Component } from 'react'

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, we'll want to add ts-jest to our devDependencies.

yarn add --dev ts-jest

Then, we'll open up our package.json and replace the jest field with the following:

"jest": {
  "preset": "react-native",
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js"
  ],
  "transform": {
    "^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
    "\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
  },
  "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
  "testPathIgnorePatterns": [
    "\\.snap$",
    "<rootDir>/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.

yarn add --dev @types/jest @types/react @types/react-native @types/react-test-renderer

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.

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.

# Jest
#
.jest/

As a checkpoint, consider committing your files into version control.

git init
git add .gitignore # import to do this first, to ignore our files
git add .
git commit -am "Initial commit."

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.

// 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<Props, State> {
  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: Math.max(0, this.state.enthusiasmLevel - 1) });
  getExclamationMarks = (numChars: number) => Array(numChars + 1).join("!")

  render() {
    return (
      <View style={styles.root}>
        <Text style={styles.greeting}>
          Hello {this.props.name + this.getExclamationMarks(this.state.enthusiasmLevel)}
        </Text>

        <View style={styles.buttons}>
          <View style={styles.button}>
            <Button
              title="-"
              onPress={this.onDecrement}
              accessibilityLabel="decrement"
              color="red"
            />
          </View>

          <View style={styles.button}>
            <Button
              title="+"
              onPress={this.onIncrement}
              accessibilityLabel="increment"
              color="blue"
            />
          </View>
        </View>
      </View>
    )
  }
}

// styles

const styles = StyleSheet.create({
  root: {
    alignItems: "center",
    alignSelf: "center"
  },
  buttons: {
    flexDirection: "row",
    minHeight: 70,
    alignItems: "stretch",
    alignSelf: "center",
    borderWidth: 5
  },
  button: {
    flex: 1,
    paddingVertical: 0
  },
  greeting: {
    color: "#999",
    fontWeight: "bold"
  }
})

Whoa! That's a lot, but let's break it down:

  • Instead of rendering HTML elements like div, span, h1, etc., we're rendering components like View and Button. These are native components that work across different platforms.
  • Styling is specified using the StyleSheet.create function that React Native gives us. React's StyleSheets allow us to control our layout using Flexbox, and style using other constructs similar to those in CSS stylesheets.

Adding a Component Test

Now that we've got a component, let's try testing it.

We already have Jest installed as a test runner. We're going to write snapshot tests for our components, let's add the required add-on for snapshot tests:

yarn add --dev react-addons-test-utils

Now let's create a __tests__ folder in the components directory and add a test for Hello.tsx:

// components/__tests__/Hello.tsx
import React from 'react'
import renderer from 'react-test-renderer'

import { Hello } from "../Hello"

it("renders correctly with defaults", () => {
  const button = renderer.create(<Hello name="World" enthusiasmLevel={1} />).toJSON()
  expect(button).toMatchSnapshot()
})

The first time the test is run, it will create a snapshot of the rendered component and store it in the components/__tests__/__snapshots__/Hello.tsx.snap file. When you modify your component, you'll need to update the snapshots and review the update for inadvertent changes. You can read more about testing React Native components here.

Next Steps

Check out our React TypeScript tutorial where we also cover topics like state management with Redux. These same subjects can be applied when writing React Native apps.

Additionally, you may want to look at the ReactXP if you're looking for a component library written entirely in TypeScript that supports both React on the web as well as React Native.

Helpful Resources