跳至主要内容

在 React Native 中使用 TypeScript

·阅读时长 8 分钟
Ash Furrow
Artsy 的软件工程师

JavaScript!我们都喜欢它。但我们中的一些人也喜欢类型。幸运的是,有一些选项可以为 JavaScript 添加更强的类型。我最喜欢的是TypeScript,但 React Native 默认支持Flow。您更喜欢哪一个取决于您的偏好,它们各自都有自己的方法来为 JavaScript 添加类型的魔力。今天,我们将了解如何在 React Native 应用中使用 TypeScript。

这篇文章使用微软的TypeScript-React-Native-Starter 仓库作为指南。

**更新**:自从这篇博文发布以来,事情变得更加容易了。您可以通过运行一个命令来替换这篇博文中描述的所有设置

npx react-native init MyAwesomeProject --template react-native-template-typescript

但是,Babel 对 TypeScript 的支持确实存在一些限制,上面这篇博文详细介绍了这些限制。这篇文章中概述的步骤仍然有效,Artsy 仍在生产环境中使用react-native-typescript-transformer,但使用上述命令是开始使用 React Native 和 TypeScript 的最快方法。如果您需要,您随时可以稍后切换。

无论如何,玩得开心!原始博文继续在下面。

先决条件

由于您可能在多个不同的平台上进行开发,并面向多种不同类型的设备,因此基本的设置可能涉及到一些步骤。您应该首先确保您可以在没有 TypeScript 的情况下运行一个普通的 React Native 应用。按照React Native 网站上的说明开始。当您成功部署到设备或模拟器时,您就可以开始创建一个 TypeScript React Native 应用了。

您还需要Node.jsnpmYarn

初始化

在您尝试搭建一个普通的 React Native 项目后,您就可以开始添加 TypeScript 了。让我们继续这样做。

react-native init MyAwesomeProject
cd MyAwesomeProject

添加 TypeScript

下一步是将 TypeScript 添加到您的项目中。以下命令将

  • 将 TypeScript 添加到您的项目中
  • React Native TypeScript Transformer 添加到您的项目中
  • 初始化一个空的 TypeScript 配置文件,我们将在下一步配置它
  • 添加一个空的 React Native TypeScript Transformer 配置文件,我们将在下一步配置它
  • 添加 React 和 React Native 的类型定义

好的,让我们继续运行这些命令。

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

tsconfig.json 文件包含 TypeScript 编译器的所有设置。上面命令创建的默认设置大部分都很好,但打开该文件并取消注释以下行

{
/* Search the config file for the following line and uncomment it. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
}

rn-cli.config.js 包含 React Native TypeScript Transformer 的设置。打开它并添加以下内容

module.exports = {
getTransformModulePath() {
return require.resolve('react-native-typescript-transformer');
},
getSourceExts() {
return ['ts', 'tsx'];
},
};

迁移到 TypeScript

将生成的 App.js__tests_/App.js 文件重命名为 App.tsxindex.js 需要使用 .js 扩展名。所有新文件都应该使用 .tsx 扩展名(如果文件不包含任何 JSX,则使用 .ts)。

如果您现在尝试运行该应用,您会收到类似于 object prototype may only be an object or null 的错误。这是由于未能从 React 中导入默认导出以及在同一行导入命名导出造成的。打开 App.tsx 并修改文件顶部的导入语句

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

其中一部分与 Babel 和 TypeScript 如何与 CommonJS 模块交互的方式不同有关。将来,这两个模块将稳定在相同行为上。

此时,您应该能够运行 React Native 应用了。

添加 TypeScript 测试基础设施

React Native 附带了Jest,因此对于使用 TypeScript 测试 React Native 应用,我们将希望将ts-jest 添加到我们的 devDependencies 中。

yarn add --dev ts-jest

然后,我们将打开我们的 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/"
],
"cacheDirectory": ".jest/cache"
}
}

这将配置 Jest 使用 ts-jest 运行 .ts.tsx 文件。

安装依赖项类型声明

为了在 TypeScript 中获得最佳体验,我们希望类型检查器能够理解我们依赖项的形状和 API。一些库会将其包发布为带有 .d.ts 文件(类型声明/类型定义文件)的形式,这些文件可以描述底层 JavaScript 的形状。对于其他库,我们需要在 @types/ npm 范围中显式安装相应的包。

例如,这里我们需要 Jest、React、React Native 和 React Test Renderer 的类型。

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

我们将这些声明文件包保存到我们的 开发 依赖项中,因为这是一个 React Native 应用,它只在开发期间使用这些依赖项,而不是在运行时使用。如果我们要将库发布到 NPM,我们可能需要将其中一些类型依赖项添加为常规依赖项。

您可以在此处阅读更多有关获取 .d.ts 文件的信息

忽略更多文件

对于您的源代码控制,您需要开始忽略 .jest 文件夹。如果您使用的是 git,我们可以只向我们的 .gitignore 文件中添加条目。

# Jest
#
.jest/

作为检查点,请考虑将您的文件提交到版本控制中。

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

添加组件

让我们向我们的应用添加一个组件。让我们创建一个名为Hello.tsx的组件。这是一个教学组件,并非你在实际应用中会编写的组件,但它是一个非平凡的组件,展示了如何在 React Native 中使用 TypeScript。

创建一个components目录并添加以下示例。

// components/Hello.tsx
import React from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';

export interface Props {
name: string;
enthusiasmLevel?: number;
}

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: 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',
},
});

哇!内容很多,但让我们分解一下。

  • 我们不再渲染像divspanh1等 HTML 元素,而是渲染像ViewButton这样的组件。这些是跨不同平台的原生组件。
  • 样式使用 React Native 提供的StyleSheet.create函数指定。React 的样式表允许我们使用 Flexbox 控制布局,并使用类似于 CSS 中的其他结构进行样式设置。

添加组件测试

现在我们有了组件,让我们尝试测试它。

我们已经安装了 Jest 作为测试运行器。我们将为我们的组件编写快照测试,让我们添加快照测试所需的附加组件。

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

现在让我们在components目录中创建一个__tests__文件夹,并为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();
});

第一次运行测试时,它将创建渲染组件的快照并将其存储在components/__tests__/__snapshots__/Hello.tsx.snap文件中。修改组件后,需要更新快照并检查是否有意外更改。您可以在此处了解更多关于测试 React Native 组件的信息。

后续步骤

查看官方的React 教程和状态管理库Redux。编写 React Native 应用时,这些资源可能会有所帮助。此外,您可能还想查看ReactXP,这是一个完全使用 TypeScript 编写的组件库,支持 Web 上的 React 以及 React Native。

在更类型安全的 React Native 开发环境中玩得开心!