wd and cc

-- Good good study, day day up!

Typescript for React Native

#Typescript #React-Native

前几天研究 settimeout 的问题的时候,发现 react-native-background-timer 自己没有 typescript 的 type 文件,但是有人给写了一个 @types/react-native-background-timer,这个包算偏门了,都有人写了 type 文件,我感觉是时候试试看 typescript 了。

搜了一下,发现没有多少在 rn 里面使用 ts 的,有一些关于 react 的,又很奇怪,大都基于 webpack 的。后来找到一篇官方的 blog 上面的,然后结合自己的研究,找到了思路。我是基于已有项目来做的,那个 blog 是基于新项目,大同小异。

首先装几个包,这几个包里面, =typescript 提供 typescript 的编译器, react-native-typescript-transformer 提供了从 ts 代码到 js 代码的转换支持, @types 的两个包提供了 react 和 react-native 的 type 文件。

1$ yarn add -D typescript react-native-typescript-transformer @types/react @types/react-native

在项目的根目录还需要准几个文件。 tsconfig.json,你的目录里面可能已经有一个 jsconfig.json 了,那个是给 eslint 用的。tsconfig.json 同时给 typescript 和 tslint 使用。

 1{
 2  "compilerOptions": {
 3    "target": "es2015",
 4    "module": "es2015",
 5    "lib": [
 6      "es2015"
 7    ],
 8    "jsx": "react",
 9    "noEmit": true,
10    "moduleResolution": "node",
11    "strict": true,
12    "esModuleInterop": true,
13    "types": [
14       "react",
15       "react-native"
16     ],
17    "allowSyntheticDefaultImports": true
18  },
19  "include": [
20     "./app/**/*"
21  ],
22  "exclude": [
23    "node_modules"
24  ]
25}

这里面的 include/exclude 按照需要调整,注意里面没有 output,我们并不需要 typescript 输出 js 文件。(当然,也可以用输出 js 文件的方式来做这个事情,但是这样就不太好自动化了,细节不说了)

然后还需要一个 rn-cli.config.js,这个是给 react-native-typescript-transformer 用的。

1module.exports = {
2  getTransformModulePath() {
3    return require.resolve('react-native-typescript-transformer');
4  },
5  getSourceExts() {
6    return ['ts', 'tsx'];
7  }
8}

然后就可以写一些 .ts 文件了。 .ts 文件表示只有 js 代码, .tsx 文件表示里面有 react 代码。写完之后可以执行一下 yarn tsc 看看,是否有错误。没有错误的话,也可以在模拟器里面看看自己的 ts 代码是不是确实可以执行。

你的代码可以在模拟器里面执行,主要是下面这段代码的作用。 ts.transpileModule 会把 ts 代码转换成 js 代码,最终执行的是 js 代码。这里有一个需要注意的地方就是这里不管 ts 的语法错误,也就是你比如定义了一个 type 是 string 类型的变量,你给他做了 number 类型的赋值,这个在 js 里面是可以的,ts 是不允许的,但是这里并不会看到错误。执行 yarn tsc 可以看到错误提示。

 1module.exports.transform = function(src, filename, options) {
 2  if (typeof src === 'object') {
 3    // handle RN >= 0.46
 4    ;({ src, filename, options } = src)
 5  }
 6
 7  if (filename.endsWith('.ts') || filename.endsWith('.tsx')) {
 8    const tsCompileResult = ts.transpileModule(src, {
 9      compilerOptions,
10      fileName: filename,
11      reportDiagnostics: true,
12    })
13
14    const errors = tsCompileResult.diagnostics.filter(
15      ({ category }) => category === ts.DiagnosticCategory.Error
16    )
17.....

所以保证代码符合 typescript 有下面几个方法:

为了保证这个,我在 git 的 commit-hook 里面增加了一个 hook。放到 .git/hooks/pre-commit 就可以。

1#!/bin/sh
2
3has_ts_file=`git diff --cached --name-status | awk '$1 != "D" { print $2 }' | grep '.ts$' |wc -l`
4
5exec 1>&2
6
7if [ "$has_ts_file" -ge '1' ];then
8    yarn tsc
9fi

但是 git 的 hooks 文件并不是 repo 的一部份,如何保证大家都是一样的配置呢?有一个 npm 包可以做这个事情。。 yarn add -D pre-commit ,然后在 package.json 里面增加一些配置。

 1    "scripts": {
 2        "start": "node node_modules/react-native/local-cli/cli.js start",
 3        "test": "jest",
 4        "lint": "node_modules/.bin/eslint app",
 5        "version": "./version-ios.sh",
 6        "precommit": "./pre-commit"
 7    },
 8    "pre-commit": [
 9        "precommit"
10    ],

scripts 里面的 precommit 和 pre-commit 是新加的。那个 pre-commit 就是上面的那个脚本,放到项目目录一起管理就可以。

comments powered by Disqus