TypeScript React Native入门

上一篇我们介绍了TypeScript如何跟React搭配使用,这篇我们继续介绍如何在React Native中使用TS。

关于React Native,我之前写过一本React Native电子书, 如果不熟悉RN的话可以参考一下。

本文涵盖内容如下:

  • TypeScript & React Native
  • TSLint
  • Jest

准备知识

本文假设读者已经知道如何用RN进行开发,至少是把开发环境搭建起来,能在模拟器或者手机上运行App了。如果不了解的话, 请参考React Native 移动开发入门与实战

新建项目

react-native init正常初始化一个RN项目。

react-native init TSReactNativeDemo

项目初始结构为:

➜  TSReactNativeDemo tree -L 1
.
├── App.js
├── __tests__
├── android
├── app.json
├── index.js
├── ios
├── node_modules
├── package.json
└── yarn.lock

4 directories, 5 files

运行

在手机或者模拟器上运行起来。

react-native run-android
react-native run-ios

引入TypeScript

目前React Native Packager是通过Babel编译.js文件以及打包的,暂时还没有特别好的方法直接使用.tsx。所以基本思路就是, 先用TypeScript的编译器tsc.ts.tsx文件编译成.js文件,再用React Native Packager编译打包即可。

首先我们安装TS依赖:

yarn add -D typescript

然后需要安装types:

yarn add -D @types/react @types/react-native

然后需要配置tsconfig.json,可以用如下命令生成:

tsc --init --pretty --sourceMap --target es2015 --outDir ./lib --rootDir ./ --module commonjs --jsx react

生成的文件里面有具体每个参数的含义,也可以参考TS官网文档。 也可以直接参考上一篇中的tsconfig.json文件,进行少许修改即可。

编写TS组件

上面配置好TS后, 我们就可以开始用TS写组件了。还是跟上篇一样, 写一个简单的Counter.tsx

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

interface Props {
  name: string;
  count?: number;
  onInc?: () => void;
  onDec?: () => void;
}

export default ({ name, count = 1, onInc, onDec }: Props) => (
  <View style={styles.root}>
    <Text>
      Counter {name}: {count}
    </Text>
    <View>
      <Button title="+" onPress={onInc || (() => {})} />
      <Button title="-" onPress={onDec || (() => {})} />
    </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',
  },
});

然后我们执行./node_modules/.bin/tsc命令,就会在lib目录下生成相同目录结构的.js文件等。

➜  TSReactNativeDemo git:(master) ✗ tree lib -L 3
lib
└── src
    └── components
        ├── Counter.js
        └── Counter.js.map

2 directories, 2 files

然后在App.js中如下使用Counter即可:

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

import Counter from './lib/src/components/Counter';

export default () => (
  <View style={styles.container}>
    <Text style={styles.welcome}>Welcome to React Native!</Text>
    <Counter name="counter1" count={10} />
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

由于lib/目录下的文件是编译生成,因此不需要放在git里面, 我们在.gitingore中添加lib/忽略之:

# TypeScript
lib/

测试

注意enzyme测试ReactNative需要用react-native-mock, 但是react-native-mock目前不支持React v16+, 因此暂时不采用enzyme吧。

RN还是用Jest做测试,为了支持TS,我们安装ts-jest包。

yarn add -D ts-jest

同样,我们也添加相应的@types

yarn add -D @types/jest @types/react-test-renderer

修改package.json文件里面jest属性:

"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/",
        "<rootDir>/lib/"
    ],
    "cacheDirectory": ".jest/cache"
}

然后我们就可以写测试代码了:

// src/components/Counter.test.tsx
import * as React from 'react';
import * as enzyme from 'enzyme';
import Counter from './Counter';

it('renders the correct text when count is not given', () => {
  const hello = enzyme.shallow(<Counter name="counter1" />);
  expect(hello.find('.counter').text()).toEqual('Counter counter1: 1');
});

更多关于Jest测试可以参考测试 Jest

配置TSLint

不像上一篇用react-scripts-ts的话TSLint是自动配置好的, 我们需要手动安装TSLint。

yarn add -D tslint tslint-react

然后把上一章的tslint.json文件复制过来。再在package.json文件中增加如下代码:

    "lint": "tslint -c tslint.json 'src/**/*.{ts,tsx}'",

然后就可以用yarn lint检查代码了。

为了在写代码的时候就能在VSCode里面获得错误提示, 可以安装VSCode的TSLint插件。

其他

最后我们做一些额外工作提高开发效率。首先我们将tsc命令写到package.json里, 同时提供一个选择开启watch模式。这样子执行yarn tsc-watch命令后, TS就能实时编译为JS了,再配合上RN的Live Reload或者Hot Reloading能大大提高开发效率。

    "tsc": "tsc",
    "tsc-watch": "tsc --watch",

Redux在RN中使用跟在React中使用没什么区别,参考TypeScript React入门即可。

本文代码托管在https://github.com/magicly/TSReactNativeDemo ,随意使用~

Refers