Typescript for 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 文件。
$ yarn add -D typescript react-native-typescript-transformer @types/react @types/react-native
在项目的根目录还需要准几个文件。 tsconfig.json,你的目录里面可能已经有一个 jsconfig.json
了,那个是给 eslint 用的。tsconfig.json 同时给 typescript 和 tslint 使用。
{
"compilerOptions": {
"target": "es2015",
"module": "es2015",
"lib": [
"es2015"
],
"jsx": "react",
"noEmit": true,
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"types": [
"react",
"react-native"
],
"allowSyntheticDefaultImports": true
},
"include": [
"./app/**/*"
],
"exclude": [
"node_modules"
]
}
这里面的 include/exclude 按照需要调整,注意里面没有 output,我们并不需要 typescript 输出 js 文件。(当然,也可以用输出 js 文件的方式来做这个事情,但是这样就不太好自动化了,细节不说了)
然后还需要一个 rn-cli.config.js,这个是给 react-native-typescript-transformer
用的。
module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
}
}
然后就可以写一些 .ts
文件了。 .ts
文件表示只有 js 代码, .tsx
文件表示里面有 react 代码。写完之后可以执行一下 yarn tsc
看看,是否有错误。没有错误的话,也可以在模拟器里面看看自己的 ts 代码是不是确实可以执行。
你的代码可以在模拟器里面执行,主要是下面这段代码的作用。 ts.transpileModule
会把 ts 代码转换成 js 代码,最终执行的是 js 代码。这里有一个需要注意的地方就是这里不管 ts 的语法错误,也就是你比如定义了一个 type 是 string 类型的变量,你给他做了 number 类型的赋值,这个在 js 里面是可以的,ts 是不允许的,但是这里并不会看到错误。执行 yarn tsc
可以看到错误提示。
module.exports.transform = function(src, filename, options) {
if (typeof src === 'object') {
// handle RN >= 0.46
;({ src, filename, options } = src)
}
if (filename.endsWith('.ts') || filename.endsWith('.tsx')) {
const tsCompileResult = ts.transpileModule(src, {
compilerOptions,
fileName: filename,
reportDiagnostics: true,
})
const errors = tsCompileResult.diagnostics.filter(
({ category }) => category === ts.DiagnosticCategory.Error
)
.....
所以保证代码符合 typescript 有下面几个方法:
- 使用支持 typescript 的编辑器,依靠编辑器的提示。vs code 配合 tslint 可以做到这个。
- 提交代码之前执行
yarn tsc
验证代码没问题之后再提交。 - 在 git 的 commit-hook 里面增加一个 hook 自动执行
yarn tsc
检查。git 也可以在 server 端做这个检查。
为了保证这个,我在 git 的 commit-hook 里面增加了一个 hook。放到 .git/hooks/pre-commit
就可以。
#!/bin/sh
has_ts_file=`git diff --cached --name-status | awk '$1 != "D" { print $2 }' | grep '.ts$' |wc -l`
exec 1>&2
if [ "$has_ts_file" -ge '1' ];then
yarn tsc
fi
但是 git 的 hooks 文件并不是 repo 的一部份,如何保证大家都是一样的配置呢?有一个 npm 包可以做这个事情。。 yarn add -D pre-commit
,然后在 package.json 里面增加一些配置。
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"lint": "node_modules/.bin/eslint app",
"version": "./version-ios.sh",
"precommit": "./pre-commit"
},
"pre-commit": [
"precommit"
],
scripts 里面的 precommit 和 pre-commit 是新加的。那个 pre-commit 就是上面的那个脚本,放到项目目录一起管理就可以。