前端小哥哥:如何使用typescript开发实战项目?
liuian 2025-09-04 11:56 24 浏览
前言
笔者上一篇文章:
主要写了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.ts和global.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游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在《趣谈前端》专栏学习讨论,共同探索前端的边界。
相关推荐
- office和visio安装顺序(office和visio怎么一起安装)
-
在某些情况下,安装Visio可能会发生与Office365冲突的问题。这是因为Visio和Office365具有不同的版本,可能会导致安装时出现错误或兼容性问题。为了避免这种冲突,...
- 电脑中病毒的原因(电脑中病毒正常吗)
-
电脑中毒的原因有以下几方面:1.网页被挂病毒。2.电脑裸奔,无防病毒软件。3.执行一些不安全的程序。4.U盘等不安全介质。5.电脑漏洞不及时补,被后台种毒。为了电脑不中病毒要注意以下几方面:1.更新系...
- 手机psd转换成jpg最简单方式
-
可以使用photoshop工具,方法如下:1、首先打开PS软件,然后选择自己需要的JPG格式的图片,在PS中打开。2、接下来先按快捷键“Ctrl+j”将图片复制出来,防止后面操作对原图片有损...
- win7提示激活码过期怎么办(win7激活已过期)
-
以win7为例,出现这样的问题原因分析:电脑的win7系统激活过又重新提示要激活的原因是因为微软对网络上的秘钥进行封杀所以导致我们激活无效。具体的解决方法:1、我们打开dos命令窗口,在创立中输入“s...
- 联想笔记本光驱驱动下载(联想电脑光驱驱动器在哪)
-
开机时进入BIOS,具体按什么牌子不同,按键也不同,开机有提示的,选择启动项,把光驱启动的顺序放到第一.按F10保存,重新启动就是光驱启动啦不需要设置光驱驱动,笔记本自带光驱驱动光驱是电脑的硬件设备,...
- win10装机必备实用软件(win10电脑装机必备软件)
-
1、office大部分的版本如office2007、office2000、office2011、office2013、office2016、office365等都支持win10。2、需要注意...
- 迅雷无法下载的链接用什么下载
-
1.可以使用其他下载工具代替迅雷。2.迅雷可能无法下载的原因有很多,比如网络问题、软件故障等。其他下载工具可以提供类似的功能,但可能具有更好的稳定性和兼容性。3.一些常见的替代迅雷的下载工具包括...
- apple官方网站(apple官方网站旗舰店)
-
1、首先打开浏览器,输入https://www.apple.com/;2、即可浏览苹果官网。 苹果公司(AppleInc.)是美国一家高科技公司。由史蒂夫·乔布斯、斯蒂夫·沃兹尼亚克和罗·韦恩(R...
- 哪些手机用鸿蒙系统(都什么手机能用鸿蒙系统)
-
截至目前,国内有以下几款手机品牌可以装鸿蒙系统:1.华为:华为Mate40系列、P40系列、Mate30系列、MatePadPro系列等。2.荣耀:荣耀V40、荣耀30系列、荣耀X10系列等...
- 手机u盘读不出来了怎么修复(手机u盘读取不出来)
-
1、手机不支持OTG功能,所以将U盘连接到手机后,手机无法识别U盘的内容,因此显示不了;这种情况只能换台支持OTG功能的手机来连接U盘才行。2、手机支持OTG功能,但是使用的OTG线质量有问题导致无法...
- 笔记本散热器买哪种好(笔记本散热器买哪种好贴吧)
-
散热器有十大品牌:九州风神、超频三,酷冷至尊Tt、AVC、思民、捷冷、安钛克Antec、安耐美Enermax、海盗船Corsair。能位列十大品牌,每一种的质量和功能都有保障。、目前网上销量最高的是九...
-
- 打印机驱动一直安装失败(打印机驱动一直安装失败怎么办)
-
打印机驱动程序安装失败需要对电脑进行其他设置,详细步骤如下:1,在电脑桌面上找到【计算机】并用鼠标右击。2,右击后在出现的选项中找到【管理】选项并点击打开。3,接下里会进入到计算机控制台界面,在这里要根据自己的电脑选择64位或者32位,选择...
-
2026-01-14 12:55 liuian
- ctrl加谁是截图(ctrl和什么键可以截图)
-
第一种:Ctrl+PrScrn使用这个组合键截屏,获得的是整个屏幕的图片第二种:Alt+PrScrn这个组合键截屏,获得的结果是当前窗口的图片第三种:打开qq,使用快捷键Ctrl+...
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
