目录
React中创建TS项目
TS目录结构
React函数组件类型
React类组件类型
如果你已经掌握了TS中基础类型、高级类型的使用,还想在前端项目中更深一层的使用TS,还需要掌握React、Vue、Angular等框架和框架提供的API,懂得如何在框架中使用TS,今天讲解如何在React项目中使用TS。如果想学习TS相关知识,推荐看一下我之前的专栏对TypeScript的相关讲解:TypeScript专栏 。
React中创建TS项目
如果不了解React脚手架搭建可以看下我之前的文章:超详细教程——React脚手架的搭建与使用
React的脚手架create-react-app(简称:CPA)默认支持TypeScript。React中创建TS的命令如下:
npx create-react-app 项目名称 --template typescript
出现如下表明React脚手架创建TS项目成功!
将创建项目的文件夹拖到编辑器上新建终端运行npm start命令即可运行项目:
上面这种是新建的使用TS的React项目,那么如何在已有的项目中使用TS呢?要知道普通的项目都是以JS项目创建的,看看官方文档怎么给出解决办法 :Adding TypeScript 。
# npm安装
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
# yarn安装
yarn add typescript @types/node @types/react @types/react-dom @types/jest
总结
我们之前在不使用TS时,会使用prop-types库,为React组件提供类型检查,而在使用TS后,其提供的组件类型校验代替了PropTypes,所以说不管是React还是Vue,只要是支持TS的库,都提供了很多类型来满足该库对类型的需求。
推荐一个网站:React+TS备忘单 ,里面详细介绍了很多React+TS的技巧。
TS目录结构
相对于非TS项目,目录结构主要发生以下的变化。
1)项目根目录中增加了tsconfig.json配置文件:指定TS的编译选项(例如:编译时是否移除注释)。
tsconfig.json文件中其配置文件选项的具体功能如下:
{
// 编译选项
"compilerOptions": {
// 生成代码的语言版本
"target": "es5",
// 指定要包含在编译中的 library
"lib": [
"dom",
"dom.iterable",
"esnext"
],
// 允许 ts 编译器编译的 js 文件
"allowJs": true,
// 跳过声明文件的类型检查
"skipLibCheck": true,
// es模块互操作,屏蔽 esModule 和 CommonJS 之间的差异
"esModuleInterop": true,
// 允许通过 import x from 'y' 即使模块没有显式指定 default 导出
"allowSyntheticDefaultImports": true,
// 开启严格模式
"strict": true,
// 对文件名称强制区分大小写
"forceConsistentCasingInFileNames": true,
// 为 switch 语句启用错误报告
"noFallthroughCasesInSwitch": true,
// 生成代码的模块化标准
"module": "esnext",
// 模块解析查找的策略
"moduleResolution": "node",
// 允许导入扩展名为 .json 的模块
"resolveJsonModule": true,
// 是否将没有 import/export 的文件视为旧 (全局而非模块化) 的脚本文件
"isolatedModules": true,
// 编译时不生成任何文件(只进行类型检查)
"noEmit": true,
// 指定将 JSX 编译成什么形式
"jsx": "react-jsx"
},
// 指定允许 ts 处理的目录
"include": [
"src"
]
}
注意:TS的配置项非常多(100+),以CPA项目中的为例,如上面的配置文件,如果想使用其它的配置,查阅 官方文档 即可。
1)tsconfig.json文件所在目录为项目根目录(与package.json同级)
2)tsconfig.json可以自动生成,无需执行 tsc --init 命令进行生成
2)React组件的文件扩展名变为:*.tsx。
3)src目录中增加了react-app-env.d.ts:React项目默认的类型声明文件。
react-scripts的类型声明文件包含了两部分类型:
1)react、react-dom、node的类型
2)图片、样式等模块的类型,以允许在代码中导入图片、SVG等文件。
TS会自动加载该.d.ts文件,以提供类型声明(通过修改tsconfig.json中的include配置来验证)。
接下来的讲解会以React17为主,所以创建的TS项目要对react和react-dom进行降级,不清楚的可以看一下我上文提到的创建React脚手架的教程。
React函数组件类型
React是组件化开发模式,React开发主要任务就是写组件,常用的函数组件包括以下几点:
组件的类型和属性(props)
import { FC } from 'react'
import ReactDOM from 'react-dom'
type Props = {name:string; age?:number}
// 完全按照函数在TS中的写法
// const Hello: FC<Props> = ({name,age})=>{
// return <div>
// 你好,我叫: {name}, 我今年{age}岁了
// </div>;
// }
// FC是一个函数式组件,是在TypeScript使用一个泛型,FC就是FunctionComponent的缩写
const Hello: FC<Props> = ({name,age})=>{
return <div>
你好,我叫: {name}, 我今年{age}岁了
</div>;
}
const App =()=>{
return <div>
<Hello name='张三' age={18} />
</div>
}
ReactDOM.render(<App />,document.getElementById('root'))
组件属性的默认值(defaultProps)
import { FC } from 'react'
import ReactDOM from 'react-dom'
type Props = {name:string; age?:number}
const Hello: FC<Props> = ({name,age})=>{
return <div>
你好,我叫: {name}, 我今年{age}岁了
</div>;
}
// 给可选属性age添加默认值
Hello.defaultProps = {
age:18
}
const App =()=>{
return <div>
<Hello name='张三' />
</div>
}
ReactDOM.render(<App />,document.getElementById('root'))
事件绑定和事件对象
import React from 'react';
import ReactDOM from 'react-dom'
// 当然也可以完全简化采用函数在TS中的写法
const Hello = ()=>{
// 点击事件
const onClick = (e: React.MouseEvent<HTMLButtonElement>)=>{
console.log('打印当前元素',e.currentTarget);
}
// 监听事件
const onChange = (e: React.ChangeEvent<HTMLInputElement>)=>{
console.log(e.target.value)
}
return <div>
<button onClick={onClick}>点我触发事件</button>
<input type="text" onChange={onChange} />
</div>;
}
const App =()=>{
return <div>
<Hello />
</div>
}
ReactDOM.render(<App />,document.getElementById('root'))
在JSX中写事件处理程序(e=>{}),然后把鼠标放到e上,利用TS的类型推论来查看事件对象类型。
React类组件类型
class组件的常用类型,主要包括以下内容:
组件类型
type State = {count:number}
type Props = {message?:string}
class C1 extends React.Component {} // 无props、state
class C2 extends React.Component<Props> {} // 有props,无state
class C3 extends React.Component<{},State> {} // 无props,有state
class C4 extends React.Component<Props,State> {} // 有props、state
组件属性
import React from 'react';
import ReactDOM from 'react-dom'
type Props = {name:string;age?:number}
class Hello extends React.Component<Props> {
// 提供属性的默认值
static defaultProps: Partial<Props> = {
age: 20
}
render(): React.ReactNode {
const {name,age} = this.props
return (
<div>
你好,我叫:{name},今年{age}岁了
</div>
)
}
}
const App =()=>{
const person = {name:'张三'}
return <div>
<Hello {...person} />
</div>
}
ReactDOM.render(<App />,document.getElementById('root'))
组件状态和事件
import React from 'react';
import ReactDOM from 'react-dom'
type State = {count:number}
class Count extends React.Component<{},State> {
// 定义状态
state: State = {
count:0
}
addCount = ()=>{
this.setState({
count:this.state.count + 1
})
}
render(): React.ReactNode {
return (
<div>
计数器:{this.state.count}
<br />
<button onClick={this.addCount}>+1</button>
</div>
)
}
}
const App =()=>{
return <div>
<Count />
</div>
}
ReactDOM.render(<App />,document.getElementById('root'))