百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

前端小哥哥:如何使用typescript开发实战项目?

liuian 2025-09-04 11:56 20 浏览

前言

笔者上一篇文章:

主要写了typescript的用法和核心知识点总结, 这篇文章将通过一个实际的前端案例来教大家如何在项目中使用typescript.

你将收获

  • 如何使用umi快速搭建一个基于React + antd + typescript的前端项目
  • 中后台前端项目的目录和ts文件划分
  • 在React组件中使用typescript
  • 在工具库中使用typescript
  • 互联网黑白墙案例分析

正文

在开始文章之前, 我们先看一下企业黑白墙项目的演示:

(注: 本文仅针对项目剖析和学习使用, 不做任何商业用途)

该项目是一个响应式网站, 针对PC端和H5均做了一定的适配, 接下来我们将正对该网站做一次typescript剖析.

由上面的gif可以看出网站的信息结构图大致如下:

接下来进入我们的正文.

1. 使用umi快速搭建一个基于React+antd+typescript的前端项目

umi是一个功能强大且开箱即用的企业级项目脚手架, 这里笔者直接采用umi来创建一个ts项目, 具体方式如下:

// 1.创建项目空目录
$ mkdir ts-react && cd ts-react

// 2.创建项目
yarn create @umijs/umi-app

// 3.安装项目依赖
yarn

用umi开发只需要简单的3个命令即可, 值得注意的是, 在执行步骤2时会在命令行出现如下交互选项:

主要是让我们选择创建的项目类型的, 这里我们选typescript和antd即可, 有关如何创建可交互的命令行工具, 在笔者的 基于react/vue生态的前端集成解决方案探索与总结 中有介绍, 感兴趣的可以学习交流.

经过以上的步骤我们就初步搭建了一个支持react + typescript + antd技术栈的项目骨架.

2. 中后台前端项目的目录和ts文件划分

我们先看看本次研究的项目的目录划分:

ts-react                                   
├─ src                               
│  ├─ assets                         
│  │  └─ yay.jpg                     
│  ├─ components                     
│  │  └─ PublicModal                 
│  │     ├─ index.css                
│  │     ├─ index.tsx                
│  │     └─ type.ts                  
│  ├─ layouts                        
│  │  ├─ __tests__                   
│  │  │  └─ index.test.tsx           
│  │  ├─ index.css                   
│  │  └─ index.tsx                   
│  ├─ locales                        
│  │  └─ en-US.ts                    
│  ├─ models                         
│  ├─ pages                          
│  │  ├─ __tests__                   
│  │  │  ├─ __mocks__                
│  │  │  │  └─ umi-plugin-locale.ts  
│  │  │  └─ index.test.tsx           
│  │  ├─ about                       
│  │  │  ├─ components               
│  │  │  ├─ index.d.ts               
│  │  │  ├─ index.less               
│  │  │  └─ index.tsx                
│  │  ├─ index.css                   
│  │  ├─ index.tsx                   
│  │  ├─ innerRec.tsx                
│  │  └─ list.tsx                    
│  ├─ utils                          
│  │  ├─ tool.ts                     
│  │  └─ type.ts                     
│  ├─ app.ts                         
│  └─ global.css                     
├─ global.d.ts                       
├─ package.json                      
├─ readme.md                         
├─ tsconfig.json                     
└─ typings.d.ts

我们从外往里看, 在项目根目录下有typings.d.tsglobal.d.ts这两个文件, 前者我们可以放置一些全局的导出模块,比如css,less, 图片的导出声明, 这样我们就不用一个个的在页面代码里再重新声明了, 如下:

// typings.d.ts
declare module '*.css';
declare module '*.less';
declare module "*.png";
declare module "*.jpeg";

这样做我们就能避免在页面中导入css或者图片文件时ts报错的问题了. 对于global.d.ts, 笔者建议放一些全局声明的变量, 接口等, 比如说Jquery这种第三方库的声明, window下全局变量的声明等.

其次是src目录,我们具体介绍一下目录的意义: assets 存放静态资源如图片/视频/音频等, 参与webpack的打包过程 layouts 存放公共布局 components 存放全局共同组件 locales 多语言配置目录 models dva的models文件夹, 处理redux流 pages 存放页面的目录, 内部可以有页面组件components, 结构类似于全局的components * utils 存放js工具库, 请求库等公共js文件

在了解了上面的目录和目录的含义之后, 我们再来看看如何规划其中的ts文件.

对于组件库来说, 其下面的一个子目录对应一个组件, 里面包含必须的样式文件, 组件tsx文件和组件自有类型文件, 这里命名为type.ts, 专门存放该组件所需要的类型和接口声明.

同理对于页面文件夹来说, 也应具有类似的结构, 就好比上面的about页面, 包含如下结构: components 该页面专有的组件目录 index.tsx 关于页面的主文件 index.less 关于页面的样式文件 type.ts 关于页面的类型和接口声明文件

还需要说明一点的是, 如果某个页面有私有的类型或者接口声明,我们可以直接在文件内部去声明, 没必要全部都拿到外面去定义和声明.

目录规划这块基本完成, 实际情况还是需要根据自身项目结构来做更合理的划分, 接下来我们看看具体的typescript在业务代码中的应用.

3. 在React组件中使用typescript

这里笔者将会拿该项目的自定义上传组件以及白名单页面作为例子, 文件上传组件笔者将采用SFC(即函数组件), 白名单页面将采用类组件, 这样可以方便大家对这两中组件开发模式下的typescript开发有个全面的认知.

3.1 自定义上传组件开发

自定义上传组件我们主要应用在发布模块, 基于antd进行二次封装以便能兼容支持antd的Form模型, 如下图:

结合typescript的实现如下:

import React, { useState, useEffect, SFC, ReactNode } from 'react';
import { Upload, message } from 'antd';
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import styles from './index.less';

export interface BeforeUploadFunc {
  (file:File, fileList:FileList): boolean | Promise<File>;
}

export interface SuccessBack {
  (url: string): string;
}

export interface ChangeFunc {
  (value: string | Array<string>): void;
}

export interface IProps {
  action: string;
  listType?: string;
  showUploadList?: boolean;
  headers?: object;
  beforeUpload?: BeforeUploadFunc;
  onSuccess?: SuccessBack;
  withCredentials?: boolean;
  text?: string | ReactNode;
  imgUrl?: string;
  onChange?: ChangeFunc;
  value?: string;
}

const UploadCp:SFC<IProps> = (props:IProps) => {
    const {
        listType = 'picture-card',
        showUploadList = false,
        action = 'http://io.cc.com/api/files/free',
        headers,
        beforeUpload = handleBeforeUpload,
        onSuccess,
        withCredentials = true,
        text = '上传封面',
        imgUrl,
        onChange,
        value
    } = props

  const [loading, setLoading] = useState(false)
  const [imageUrl, setImageUrl] = useState(imgUrl)

  const handleChange = (info:FileList):void => {
    // 一些操作
  }

  function handleBeforeUpload(file:File):boolean {
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      message.error('You can only upload JPG/PNG file!');
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      message.error('Image must smaller than 2MB!');
    }
    return isJpgOrPng && isLt2M;
  }

  useEffect(() => {
    !value && setImageUrl(imgUrl)
  }, [imgUrl, value])

  return <Upload
          name="file"
          listType={listType}
          className={styles.avatarUploader}
          showUploadList={showUploadList}
          action={action}
          withCredentials={withCredentials}
          headers={headers}
          beforeUpload={beforeUpload}
          onChange={handleChange}
        >
          {(value || imageUrl) ? <img src={value || imageUrl} alt="avatar" style={{ width: '100%' }} alt={text} /> : text}
        </Upload>
}

export default UploadCp

以上代码我们使用了React的函数组件, React提供了函数组件的类型SFC, 内置了children所以我们不用显示的再声明一次. 其他的比如函数声明, 泛型接口, 可选类型的设置等笔者在上一篇文章:

徐小夕:TS核心知识点总结及项目实战案例分析

有详细介绍.不懂的可以在评论区与我交流.

3.2 白名单页面开发

在了解完函数式组件如何与typescript搭配使用之后, 我们再来看看类组件. 我们那拿搜索列表页作为例子来讲解:


代码如下:

import React from 'react';
import { List, Avatar, Button, Skeleton, Tag, Modal } from 'antd';
import styles from './index.less';
import req from '@/utils/req';

export interface IProps extends Location {

}

interface List {
  name: string;
  img: string;
  desc: string;
  isLoading?: boolean;
}

interface LoadingState {
  initLoading: boolean;
  loading: boolean;
}

export interface IState extends LoadingState {
  data: Array<List>;
  list: Array<List>;
}

class LoadMoreList extends React.Component<IProps, IState> {
  state:IState = {
    initLoading: true,
    loading: false,
    data: [],
    list: [],
  };

  componentDidMount() {
    this.getData();
  }

  getData = () => {
    req.get(`/blackwhite/get?type=${this.props.location.query.type}`).then((res:List) => {
      this.setState({
        initLoading: false,
        data: res,
        list: res.slice(0, pageNum)
      });
    })
  };

  render() {
    const { initLoading, loading, list, data } = this.state;
    return // 页面实现代码
  }
}

export default LoadMoreList

以上代码实现了class组件的typescript应用, 对于interface类型声明用到了继承, 当然也可以不用继承直接写类型声明, 这里主要为了学习方便. 大家也可以把公用的页面类型放到单独的type.ts目录下复用.

4. 在工具库中使用typescript

在掌握了类组件和函数组件的typescript写法之后, 我们来说说工具类的typescript编写方式, 这块比较简单, 笔者简单举几个常用工具函数, 将其改造成typescript的模式. 代码如下:

// utils/tool.ts
/*
 * @Author: Mr Jiang.Xu 
 * @Date: 2019-06-06 11:23:05 
 * @Last Modified by: Mr Jiang.Xu
 * @Last Modified time: 2019-06-29 22:33:52
 */

/**
 * 识别ie--浅识别
 */
export const isIe = ():boolean => {
    let explorer = window.navigator.userAgent;
        //判断是否为IE浏览器
    if (explorer.indexOf("MSIE") >= 0) {
        return true;
    }else {
        return false
    }
}

/**
 * 颜色转换16进制转rgba
 * @param {String} hex 
 * @param {Number} opacity 
 */
export function hex2Rgba(hex:string, opacity:number):string {
    if(!hex) hex = "#2c4dae";
    return "rgba(" + parseInt("0x" + hex.slice(1, 3)) + "," + parseInt("0x" + hex.slice(3, 5)) + "," + parseInt("0x" + hex.slice(5, 7)) + "," + (opacity || "1") + ")";
}

// 去除html标签
export const htmlSafeStr = (str:string):string => {
    return str.replace(/<[^>]+>/g, "")
}


interface params {
  [propertyName: string]: string | number
}
/* 解析url参数 */
export const toParams = (params:params):string => {
    if(params){
        let query = [];
        for(let key in params){
            query.push(`${key}=${params[key]}`)
        }
        return `${query.join('&')}`
    }else{
        return ''
    }
}

以上是几个比较简单的案例, 方便大家入门和理解, 实际工作中场景会更复杂, 但是掌握了基本声明和定义模式, 基本可以解决大部分ts声明问题. 作为一名前端工程师, typescript的意义很大,虽然它增加了编程的复杂度和学习成本, 但是长远来说, 对于团队的编码规范, 问题定位, 项目维护和代码管理的角度确实有不少积极作用, 所以学习typescript刻不容缓.

最后

如果想学习更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在《趣谈前端》专栏学习讨论,共同探索前端的边界。

相关推荐

搭建一个20人的办公网络(适用于20多人的小型办公网络环境)

楼主有5台机上网,则需要一个8口路由器,组网方法如下:设备:1、8口路由器一台,其中8口为LAN(局域网)端口,一个WAN(广域网)端口,价格100--400元2、网线N米,这个你自己会看了:)...

笔记本电脑各种参数介绍(笔记本电脑各项参数新手普及知识)

1、CPU:这个主要取决于频率和二级缓存,频率越高、二级缓存越大,速度越快,现在的CPU有三级缓存、四级缓存等,都影响相应速度。2、内存:内存的存取速度取决于接口、颗粒数量多少与储存大小,一般来说,内...

汉字上面带拼音输入法下载(字上面带拼音的输入法是哪个)

使用手机上的拼音输入法打成汉字的方法如下:1.打开手机上的拼音输入法,在输入框中输入汉字的拼音,例如“nihao”。2.根据输入法提示的候选词,选择正确的汉字。例如,如果输入“nihao”,输...

xpsp3安装版系统下载(windowsxpsp3安装教程)

xpsp3纯净版在采用微软封装部署技术的基础上,结合作者的实际工作经验,融合了许多实用的功能。它通过一键分区、一键装系统、自动装驱动、一键设定分辨率,一键填IP,一键Ghost备份(恢复)等一系列...

没有备份的手机数据怎么恢复

手机没有备份恢复数据方法如下1、使用数据线将手机与电脑连接好,在“我的电脑”中可以看到手机的盘符。  2、将手机开启USB调试模式。在手机设置中找到开发者选项,然后点击“开启USB调试模式”。  3、...

电脑怎么激活windows11专业版

win11专业版激活方法有多种,以下提供两种常用的激活方式:方法一:使用激活密钥激活。在win11桌面上右键点击“此电脑”,选择“属性”选项。进入属性页面后,点击“更改产品密钥或升级windows”。...

华为手机助手下载官网(华为手机助手app下载专区)

华为手机助手策略调整,已不支持从应用市场下载手机助手,目前华为手机助手是需要在电脑上下载或更新手机助手到最新版本,https://consumer.huawei.com/cn/support/his...

光纤线断了怎么接(宽带光纤线断了怎么接)

宽带光纤线断了可以重接,具体操作方法如下:1、光纤连接的时候要根据束管内,同色相连,同芯相连,按顺序进行连接,由大到小。一般有三种连接方法,分别是熔接、活动连接和机械连接。2、连接的时候要开剥光缆,抛...

深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
win7旗舰版和专业版区别(win7旗舰版跟专业版)

1、功能区别:Win7旗舰版比专业版多了三个功能,分别是Bitlocker、BitlockerToGo和多语言界面; 2、用途区别:旗舰版的功能是所有版本中最全最强大的,占用的系统资源,...

万能连接钥匙(万能wifi连接钥匙下载)

1、首先打开wifi万能钥匙软件,若手机没有开启WLAN,就根据软件提示打开WLAN开关;2、打开WLAN开关后,会显示附近的WiFi,如果知道密码,可点击相应WiFi后点击‘输入密码’连接;3、若不...

雨林木风音乐叫什么(雨林木风是啥)

雨林木风的创始人是陈年鑫先生。陈年鑫先生于1999年创立了雨林木风公司,其初衷是为满足中国市场对高品质、高性能电脑的需求。在陈年鑫先生的领导下,雨林木风以技术创新、产品质量和客户服务为核心价值,不断推...

aics6序列号永久序列号(aics6破解序列号)

关于AICS6这个版本,虽然是比较久远的版本,但是在功能上也是十分全面和强大的,作为一名平面设计师的话,AICS6的现有的功能已经能够应付几乎所有的设计工作了……到底AICC2019的功能是不是...

win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
手机可以装电脑系统吗(手机可以装电脑系统吗怎么装)

答题公式1:手机可以通过数据线或无线连接的方式给电脑装系统。手机安装系统需要一定的技巧和软件支持,一般需要通过数据线或无线连接的方式与电脑连接,并下载相应的软件和系统文件进行安装。对于大部分手机用户来...