本文详细介绍了如何使用 Create-React-App 编写 TypeScript + React 项目css
对于 TypeScript + React 开发,MicroSoft 编写了一个 TypeScript-React-Starter 的例子,Github 地址。有须要的朋友能够去看一下。html
我本身也看了一下,文档说明讲解的很好,可是 Demo 拉下来却没法正常运行,一直报错。因此我本身使用 TypeScript + React + Redux 写了 Demo,做为范例来用一下。node
本文 Counter Demo 是一个简易的例子,能够用来做为入门参考,Counter Demoreact
另外还写了一个 TodoList 的例子,稍微更有难度一些,代码量和组件更多更详细。有须要的朋友也能够参考一下。TodoList Demogit
能够先下载 Counter Demo 后,运行项目,查看运行效果,而后对照本文进行阅读,效果更佳!github
TypeScript
编写 React
须要注意的规范必须遵照的要求:typescript
jsx
语法的文件都须要以 tsx
后缀命名Component<P, S>
泛型参数声明,来代替 PropTypes
进行类型校验额外的代码规范:npm
window
对象属性,统一在项目根下的 global.d.ts
中进行声明定义types/
目录下定义好其结构化类型声明$ npm install create-react-app -g
复制代码
$ create-react-app typescript-react-app --scripts-version=react-scripts-ts
复制代码
react-scripts-ts是一系列适配器,它利用标准的create-react-app工程管道并把TypeScript混入进来。json
项目建立成功后,此时项目结构以下所示:redux
my-app/
├─ node_modules/
├─ public/
├─ src/
│ └─ ...
├─ .gitignore
├─ images.d.ts
├─ package.json
├─ README.md
├─ tsconfig.json
├─ tsconfig.prod.json
├─ tsconfig.test.json
├─ tslint.json
└─ yarn.lock
复制代码
先运行项目,看看是否可以正常启动,若是能够,说明项目建立没有问题。 运行命令:
$ npm run start
# 或者运行 yarn run start
复制代码
在当前项目中,能够看到 index.tsx 和 App.jsx 文件中已经使用了 TypeScript,咱们如今本身来用 TypeScript 编写一个 React 组件吧。
咱们在 src 下建立一个 components 目录,新增 Counter 组件:
Counter.tsx
import * as React from 'react';
// 建立类型接口
export interface Iprops {
value: number
}
// 使用接口代替 PropTypes 进行类型校验
const Counter = ({ value }: Iprops) => {
return <p>Clicked: { value } times</p>
}
export default Counter;
复制代码
import * as React from 'react';
import './App.css';
import Counter from './components/Counter.jsx';
// import logo from './logo.svg';
class App extends React.Component {
public render() {
return (
<div className="App">
<Counter value={ 0 } />
</div>
);
}
}
export default App;
复制代码
运行项目:npm run start
,能够看到浏览器中展现出了 Clicked: 0 times
,说明咱们第一个 Counter 组件已经编写并使用成功了。
刚才是使用函数组件的方式定义的 Counter 组件,如今咱们使用类的方式来改写一下。两种方式都试一试:
Counter.tsx
import * as React from 'react';
// 建立类型接口
export interface IProps {
value: number
}
// 使用接口代替 PropTypes 进行类型校验
export default class Counter extends React.PureComponent<IProps> {
public render() {
return <p>Clicked: { this.props.value } times</p>
}
}
复制代码
安装redux和react-redux以及它们的类型文件作为依赖。
$ npm install -S redux react-redux @types/react-redux
复制代码
这里咱们不须要安装@types/redux,由于Redux已经自带了声明文件(.d.ts文件)。
通常会将经常使用的结构类型存放到 /types 目录下。因此咱们在 src 目录下新建 types 目录。 此时项目中只有一个 state,就是 Counter 中的点击次数,因此就没有使用借口来做为约束,而是直接使用了 type。
type/index.tsx
// 定义 State 结构类型
export type StoreState = number;
复制代码
在 src 下建立 constants 目录,在 index.tsx 文件中添加须要响应的消息类型
constants/index.tsx
// 定义增长 state 类型常量
export const INCREMENT = "INCREMENT";
export type INCREMENT = typeof INCREMENT;
// 定义减小 state 类型常量
export const DECREMENT = "DECREMENT";
export type DECREMENT = typeof DECREMENT;
复制代码
这里的const/type模式容许咱们以容易访问和重构的方式使用TypeScript的字符串字面量类型。 接下来,咱们建立一些 actions 以及建立这些 actions 的函数,src/actions/index.tsx。
actions/index.tsx
export interface IINCREMENTAction {
type: INCREMENT;
}
export interface IDECREMENTAction {
type: DECREMENT;
}
// 定义 modifyAction 类型,包含 IINCREMENTAction 和 IDECREMENTAction 接口类型
export type ModifyAction = IINCREMENTAction | IDECREMENTAction;
// 增长 state 次数的方法
export const increment = (): IINCREMENTAction => ({
type: INCREMENT,
})
// 减小 state 次数的方法
export const decrement = (): IDECREMENTAction => ({
type: DECREMENT
})
复制代码
actions/index.tsx
中定义了两个类型,分别负责添加和减小操做的行为。咱们还定义了一个类型(ModifyAction
),它描述了哪些 action
是能够增长或减小的。 最后,咱们定义了两个函数用来建立实际的 actions
。
咱们的reducer将放在src/reducers/index.tsx文件里。 它的功能是保证增长操做会让 times
加1,减小操做则要将 times
减1。
reducers/index.tsx
import { ModifyAction } from '../actions';
import { DECREMENT, INCREMENT } from '../constants';
// 处理并返回 state
export default (state = 0, action: ModifyAction): number => {
switch (action.type) {
case INCREMENT:
return state + 1
case DECREMENT:
return state - 1
default:
return state
}
}
复制代码
以前咱们已经使用了 Counter 组件,可是这个组件是一个纯组件,此时咱们须要一个组件将 Counter 和 数据链接起来。咱们先修改一下原先的 Counter 组件,在其中添加一些操做按钮
components/Counter.tsx
import * as React from 'react';
// 建立类型接口
export interface IProps {
value: number,
onIncrement: () => void,
onDecrement: () => void
}
// 使用接口代替 PropTypes 进行类型校验
export default class Counter extends React.PureComponent<IProps> {
public render() {
const { value, onIncrement, onDecrement } = this.props;
return (
<p>
Clicked: { value } times
<br />
<br />
<button onClick={ onIncrement } style={{ marginRight: 20 }}> + </button>
<button onClick={ onDecrement }> - </button>
</p>
)
}
}
复制代码
而后咱们再建立一个 container
目录,用来存放须要与数据交互的组件,新建 CounterCon.tsx
文件.
两个关键点是初始的 Counter
组件和 react-redux
的 connect
函数。 connect
能够将咱们的 Counter
组件转换成一个容器,经过如下两个函数:
container/CounterCon.tsx
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { decrement, increment } from '../actions';
import Counter from '../components/Counter';
import { StoreState } from '../types';
// 将 reducer 中的状态插入到组件的 props 中
const mapStateToProps = (state: StoreState): { value: number } => ({
value: state
})
// 将 对应action 插入到组件的 props 中
const mapDispatchToProps = (dispatch: Dispatch) => ({
onDecrement: () => dispatch(decrement()),
onIncrement: () => dispatch(increment())
})
// 使用 connect 高阶组件对 Counter 进行包裹
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
复制代码
让咱们回到src/index.tsx。 要把全部的东西合到一块儿,咱们须要建立一个带初始状态的store,并用咱们全部的reducers来设置它。 而且使用 react-redux 的 Provider 将 props 和 容器链接起来
index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './App';
import './index.css';
import reducer from './reducer';
import registerServiceWorker from './registerServiceWorker';
// 一、建立 store
const store = createStore(reducer);
ReactDOM.render(
// 二、而后使用react-redux的Provider将props与容器连通起来
<Provider store={ store }>
<App />
</Provider> ,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();
复制代码
回到咱们的 App.jsx 文件中,以前咱们引用的是 components 中的 Counter 组件,可是此时咱们须要使用的是与数据有交互的 CounterCon 组件。改写以下:
App.jsx
import * as React from 'react';
import './App.css';
// 引入 container 组件 CountCon
import CountCon from './container/CountCon';
// import logo from './logo.svg';
class App extends React.Component {
public render() {
return (
<div className="App"> <CountCon /> </div>
);
}
}
export default App;
复制代码
注意,此时 CountCon
再也不须要 props
了,由于咱们使用了 connect
函数为包裹起来的 Hello
组件的 props
适配了应用的状态。
此时,运行项目,点击 + 或者 - 按钮,便可看到 times
的次数会发生变化。
至此,对于使用 TypeScript
编写 React
应用应该有了必定的了解。其实写法也比较固定,刚接触的话可能有些地方容易出现问题,多写几个组件以后,应该就没什么问题了。 在编写项目的过程当中,create-react-app
自带的 tslint
可能要求比较严严格,好比:
tslint.json
文件 rules
属性中添加:"jsx-no-lambda": false
便可tslint.json
文件 rules
属性中添加:"ordered-imports": false
便可还有不少别的配置,有须要的话,能够查看文档:TSLint core rules。
本文 Counter Demo
是一个简易的例子,能够用来做为入门参考:Counter Demo
另外还写了一个 TodoList
的例子,稍微更有难度一些,代码量和组件更多更详细。有须要的朋友也能够参考一下:TodoList Demo