Appearance
tsconfig 配置
json
{
"compilerOptions": {
"noImplicitAny": true, // 不需要显式的声明变量的类型 any (如果某数据是 any 时就不需要声明,如 var a:any = 2 可直接写成 var a = 2)
"target": "es5", // 编译后 js 版本
"lib": ["dom", "dom.iterable", "esnext"], // 告诉编译器那些库可以使用,如执行 document.getElementById 编译器就知道如何进行检查
"allowJs": true, // 允许混合编译 js 文件
"skipLibCheck": true,
"esModuleInterop": true, // 允许我们使用 commonjs 的方式引入默认文件
"allowSyntheticDefaultImports": true,
"strict": true, // 开启所有严格的类型检查
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"module": "esnext", // 配置代码的模块系统 (commonjs、esm)
"moduleResolution": "node", // 决定编译器的工作方式
"resolveJsonModule": true, // 允许引入并解析json文件
"isolatedModules": true, // 编译器会将每个文件作为单独的模块使用
"noEmit": true, // 当发生错误的时候,编译器不会生成 js 代码
"jsx": "react-jsx" // 允许编译器支持编译 react 代码
},
"include": ["src"] // 表示 ts 管理的文件
}
组件导出
js
// 在 footer 文件夹下新建 index.ts 导出 Footer 组件
export * from './Footer'
js
// 在 header 文件夹下新建 index.ts 导出 Header 组件
export * from './Header'
js
// 在 components 下新建 index.ts 导出这两个组件
export * from './header'
export * from './footer'
js
import styles from './App.module.css'
// 在其他组件中就可以这样引入
import { Header, Footer } from './components'
function App() {
return (
<div className={styles.App}>
<Header />
<Footer />
</div>
)
}
export default App
安装第三方库类型定义
js
// 如果将鼠标放置在第三方库上显示找不到类型声明文件,这就说明这个库没有提供原生 ts 支持
// 这时一般可以执行 npm i @types/xxx 来解决
在 react 中使用 ts
定义函数组件 props
typescript
import React from 'react'
// 定义 props 类型
interface PropsType {
loading: boolean
originalPrice: number
price: number
onShoppingCartClear: () => void
onCheckout: () => void
}
// 规定 props 类型
export const PaymentCard: React.FC<PropsType> = ({
loading,
originalPrice,
price,
onShoppingCartClear,
onCheckout
}) => {}
另一种方式
typescript
// 定义类型
type Props = {
// 如下类型规定为:[{ id: 1, text: "吃饭", done: false }]
list: { id: number; text: string; done: boolean }[]
}
// 规定 props 类型
export const PaymentCard = ({ list }: Props) => {}
使用路由参数定义泛型
js
// 在app组件中定义路由参数
import { Detail } from './page'
import { BrowserRouter, Route } from 'react-router-dom'
function App() {
return (
<div>
<BrowserRouter>
<Route path="/detail/:touristRouteId" component={Detail} />
</BrowserRouter>
</div>
)
}
export default App
typescript
// Detail组件
import { FC } from 'react'
// 引入路由参数 props 类型
import { RouteComponentProps } from 'react-router-dom'
// 定义路由参数接口
interface MatchParams {
touristRouteId: string
}
// FC 表示声明一个 react 函数组件类型
// 将 react-router-dom 和自定义参数接口应用给函数泛型
export const Detail: FC<RouteComponentProps<MatchParams>> = props => {
// 这样就能正常读取到 /detail 后面的路由参数了
return <h1>旅游详情{props.match.params.touristRouteId}</h1>
}
使用路由组件 withRouter
js
import React from 'react'
import { Image, Typography } from 'antd'
import { withRouter, RouteComponentProps } from 'react-router-dom'
// 需要引入 RouteComponentProps 类型声明并将 ProductImageComponent 的接口继承它才能正常使用
interface PropsType extends RouteComponentProps {
id: string | number;
size: 'large' | 'small';
imageSrc: string;
price: number | string;
title: string;
}
/////////////////////////////////////////////////////////
const ProductImageComponent: React.FC<PropsType> = ({
id,
size,
imageSrc,
price,
title
}) => {
return (
<>
{size == 'large' ? (
<Image src={imageSrc} height={285} width={490} />
) : (
<Image src={imageSrc} height={120} width={240} />
)}
<div>
<Typography.Text type="secondary">{title.slice(0, 25)}</Typography.Text>
<Typography.Text type="danger" strong>
¥{price}起
</Typography.Text>
</div>
</>
)
}
// 一般 withRouter 使用会提示找不到类型////////////////////////////////////////////
export const ProductImage = withRouter(ProductImageComponent)
class 组件使用
js
import React from 'react'
import { withRouter, RouteComponentProps } from 'react-router-dom'
// 引入 RouteComponentProps 接口定义 React.Component 的泛型这样就能使用 this.props.history
class HeaderComponent extends React.Component<RouteComponentProps> {
render() {
return (
<div className={styles['app-header']}>
<div className={styles['top-header']}>
<div className={styles['inner']}>
<Button.Group className={styles['button-group']}>
<Button
onClick={() => {
this.props.history.push('register')
}}
>
注册
</Button>
<Button
onClick={() => {
this.props.history.push('signIn')
}}
>
登录
</Button>
</Button.Group>
</div>
</div>
</div>
)
}
}
export const Header = withRouter(HeaderComponent)
js
import React from "react";
import { withRouter, RouteComponentProps } from "react-router-dom";
import store from '../../redux/store'
// 新建 State 接口约束 class 组件的 state
interface State {
language:'en'|'zh';
languageList:{name:string;code:string}[]
}
// 将自定义接口传递给 React.Component 泛型的第二个参数就可以正常约束状态
class HeaderComponent extends React.Component<RouteComponentProps,State> {
constructor(props){
super(props)
const storeState = store.getState()
this.state = {
language:storeState.language,
languageList:storeState.languageList,
}
}
render() {
return ();
}
}
export const Header = withRouter(HeaderComponent);
限制组件 props 和 state
国际化(i18next)
js
// https://react.i18next.com/ 官方文档
// npm install react-i18next i18next --save 安装依赖