前端小哥哥:如何使用typescript開發實戰專案?

前言

筆者上一篇文章:

前端小哥哥:如何使用typescript開發實戰專案?

主要寫了

typescript

的用法和核心知識點總結, 這篇文章將透過一個實際的前端案例來教大家如何在專案中使用

typescript

你將收穫

如何使用

umi

快速搭建一個基於

React

+

antd

+

typescript

的前端專案

中後臺前端專案的目錄和

ts

檔案劃分

在React元件中使用

typescript

在工具庫中使用

typescript

網際網路黑白牆

案例分析

正文

在開始文章之前, 我們先看一下

企業黑白牆

專案的演示:

前端小哥哥:如何使用typescript開發實戰專案?

趣談前端

(注: 本文僅針對專案剖析和學習使用, 不做任何商業用途)

該專案是一個響應式網站, 針對PC端和H5均做了一定的適配, 接下來我們將正對該網站做一次

typescript

剖析。

由上面的gif可以看出網站的資訊結構圖大致如下:

前端小哥哥:如何使用typescript開發實戰專案?

趣談前端

接下來進入我們的正文。

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開發實戰專案?

前端小哥哥:如何使用typescript開發實戰專案?

主要是讓我們選擇建立的專案型別的, 這裡我們選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。tsdeclare 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開發實戰專案?

趣談前端

結合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;}export interface SuccessBack { (url: string): string;}export interface ChangeFunc { (value: string | Array): 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 = (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 {(value || imageUrl) ? 前端小哥哥:如何使用typescript開發實戰專案? : text} }export default UploadCp

以上程式碼我們使用了React的函式元件, React提供了函式元件的型別

SFC

, 內建了children所以我們不用顯示的再宣告一次。 其他的比如函式宣告, 泛型介面, 可選型別的設定等筆者在上一篇文章:

徐小夕:TS核心知識點總結及專案實戰案例分析

有詳細介紹。不懂的可以在評論區與我交流。

3。2 白名單頁面開發

在瞭解完函式式元件如何與typescript搭配使用之後, 我們再來看看類元件。 我們那拿搜尋列表頁作為例子來講解:

前端小哥哥:如何使用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: Array;}class LoadMoreList extends React。Component { 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資料視覺化

等前端知識和實戰,歡迎在《趣談前端》專欄學習討論,共同探索前端的邊界。