Skip to content

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 安装依赖