React中使用TypeScript
使用 CRA 创建支持 TS 的项目
React 脚手架工具 create-react-app(简称:CRA)默认支持 TypeScript。
创建支持 TS 的项目命令:npx create-react-app 项目名称 --template typescript。
当看到以下提示时,表示支持 TS 的项目创建成功:
结构变化
相对于非 TS 项目,目录结构主要由以下三个变化:
- 项目根目录中增加了 tsconfig.json 配置文件:指定 TS 的编译选项(比如,编译时是否移除注释)。
- React 组件的文件扩展名变为:*.tsx。
- src 目录中增加了 react-app-env.d.ts:React 项目默认的类型声明文件。
React 项目默认的类型声明文件
react-app-env.d.ts:**React 项目默认的类型声明文件。
三斜线指令:指定依赖的其他类型声明文件,types 表示依赖的类型声明文件包的名称。
/// <reference types="react-scripts" />
解释:告诉 TS 帮我加载 react-scripts 这个包提供的类型声明。
react-scripts 的类型声明文件包含了两部分类型:
- react、react-dom、node 的类型
- 图片、样式等模块的类型,以允许在代码中导入图片、SVG 等文件。
TS 会自动加载该 .d.ts 文件,以提供类型声明(通过修改 tsconfig.json 中的 include 配置来验证)。
TS 配置文件 tsconfig.json
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+),以 CRA 项目中的配置为例来学习,其他的配置项用到时查文档即可。
- tsconfig.json 文件所在目录为项目根目录(与 package.json 同级)。
- tsconfig.json 可以自动生成,命令:tsc --init。
React 中的常用类型
- React 项目是通过 @types/react、@types/react-dom 类型声明包,来提供类型的。
- 这些包 CRA 已帮我们安装好(react-app-env.d.ts),直接用即可。
函数组件定义类型
函数组件的类型以及组件的属性
import React from 'react';
type Props = { name: string; age?: number }
//第一种写法
const Hello:React.FC<Props>=({ name, age }) => (<div>你好、我叫{name},今年{age}岁了</div>)
//第二种写法简化(完全按照函数在 TS 中的写法)
//const Hello = ({ name, age }:Props) => (<div>你好、我叫{name},今年{age}岁了</div>)
function App() {
return (
<div >
<Hello name='李寒松' age={18} />
</div>
);
}
export default App;
函数组件属性的默认值(defaultProps)
//指定默认值
Hello.defaultProps={
age:20
}
//指定默认值简化版
const Hello = ({ name, age=23 }:Props) => (<div>你好、我叫{name},今年{age}岁了</div>)
#### 事件绑定和事件对象
<button onClick={onClick}>点我</button>
<input onChange={onChange} />
//为点击事件指定类型
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log('我是点击事件')
}
//为输入框 事件指定类型
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value)
}
技巧:在 JSX 中写事件处理程序(e => {})
然后,把鼠标放在 e 上,利用 TS 的类型推论来查看事件对象类型。
//const onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
class 组件定义类型
class 组件的类型
type State={ count:number}
type Props={ message?:string}
//无props、无state
class C1 extends React.Component{}
//有props、无state
class C2 extends React.Component<Props>{}
//无props、有state
class C3 extends React.Component<{},State>{}
//有props,state
class C3 extends React.Component<Props,State>{}
#### class 组件的属性和属性默认值
class 组件的属性和属性默认值
type PropsLHS={ name:string;age?:number}
class Test extends React.Component<PropsLHS>{
//提供属性的默认值
//static defaultProps:Partial<PropsLHS>={age:24}
render(){
//默认值简写
const {name,age=18}=this.props
return (
<div>
你好、我叫:{name}、我{age}岁了
</div>
)
}
}
<Test name='小天'/>
class 组件的组件状态和事件
import React from 'react';
type State = { count: number }
//<{}, State>传递类型参数
export default class Counter extends React.Component<{}, State> {
//创建属性的时候提供一个类型
state: State = {count: 0}
handleClick = () => this.setState({count:this.state.count+1})
render() {
return (
<div>
<div>
计数器:{this.state.count}
<button onClick={this.handleClick}>加一</button>
</div>
</div>
);
}
}