型別即正義:TypeScript 從入門到實踐(序章)

圖雀社群發表於2020-04-06

作者:一隻圖雀
倉庫:GithubGitee
圖雀社群主站(首發):圖雀社群
部落格:掘金知乎慕課
公眾號:圖雀社群
聯絡我:關注公眾號後可以加圖雀醬微信哦
原創不易,❤️點贊+評論+收藏 ❤️三連,鼓勵作者寫出更好的教程

準備程式碼


因為需要儘可能全且精煉的講解 TypeScript 語法知識,所以我們需要一個恰到好處的實戰專案,這一小節主要是用於講解我們準備初始 TypeScript 版本的 React 專案程式碼的過程,在下一個小節中我們將會結合 React 專案程式碼,真正開始 TypeScript 語法的講解。

本文所涉及的原始碼都放在了 Github  或者 Gitee 上,如果您覺得我們寫得還不錯,希望您能給❤️這篇文章點贊GithubGitee 倉庫加星❤️哦~

此教程屬於 React 前端工程師學習路線的一部分,歡迎來 Star 一波,鼓勵我們繼續創作出更好的教程,持續更新中~

前提條件

  1. 確保你已經安裝了 Node.js,可以訪問官網安裝:官網地址
  2. 確保你已經瞭解基本的 React 開發知識,圖雀社群有一篇很好的 React 入門教程,你可以通過學習它很快的上手 React。
  3. 確保你有一定的命令列使用基礎,包括使用 Npm (Node.js 包管理工具)來安裝包。

初始化應用


初始一個 React 應用的最佳方式那麼一定是 React 官方維護的 Create React App 腳手架了,我們開啟終端,執行如下命令來初始化一個 TypeScript 版本的 React 應用:

$ npx create-react-app typescript-tea --template typescript
複製程式碼


執行如上命令,命令列裡面應該會有一系列輸出,等待幾分鐘,就會提示已經初始化完成,並提供了對於的命令來幫助你開啟專案,我們根據提示輸入如下命令來開啟專案:

$ cd typescript-tea
$ npm start
複製程式碼


執行如上命令之後,會自動開啟 Webpack 開發伺服器,並開啟瀏覽器窗戶,訪問 http://localhost:3000/ 來展示你的應用初始介面:

型別即正義:TypeScript 從入門到實踐(序章)


如果看到這個介面,恭喜你?!成功建立一個 TypeScript 版本的 React 應用!

提示 在下文中,為了簡化語言,我們統一稱 TypeScript 為 TS。

引入 antd 元件庫


實戰驅動的技術學習能帶給我們成就感,便捷好用的包可以加快我們的開發效率,好看的介面可以提高我們的審美能力,緩解學習疲勞。在這篇教程的講解過程中,我們將通過 Ant Design 對應的 React 元件庫 antd 來輔助我們專案的編寫,使得我們可以專注於講解 TS 的核心知識,而不被繁雜的介面語言所干擾,還能做出對應相應完成的目標功能。

提示 Ant Design 是螞蟻金服孵化的一套企業級產品設計體系,提供了完備的 TS 型別定義,使得我們可以很方便的在 TS 專案中使用,在最近釋出了 4.0 版本,致力於創造高效愉悅的工作體驗。 除此之外 Ant Design 的周邊生態也很豐富:

  • 包括新一代資料視覺化解決方案:AntV
  • 一個基於 Preact / React / React Native 的 UI 元件庫:Ant Design Mobile
  • 開箱即用的中臺前端/設計解決方案:Ant Design Pro
  • 插畫設計:海兔
  • 一款為設計者提升工作效率的 Sketch 工具集 : Kitchen

後面圖雀社群計劃圍繞 Ant Design 生態撰寫一系列教程,幫助大家提高設計、開發效率,敬請期待!✌️

安裝依賴


好了,大致介紹了 antd 元件庫及 Ant Design 周邊之後,我們馬上來寫程式碼引入 antd,開啟命令列,在其中輸入如下命令:

$ npm install antd
複製程式碼


執行上面的命令安裝完依賴之後就可以在專案中使用了,但是為了更好的定製樣式和按需引用以減小打包之後的包體積,我們還需要做一點定製化的操作,開啟命令列,依次安裝如下依賴:

$ npm install react-app-rewired customize-cra babel-plugin-import less less-loader
複製程式碼


注意到上面我們安裝了很多包,我們來依次解釋一下上面各種包的意思:

  • react-app-rewired:用來定製化 Create React App (CRA)腳手架的一些配置,比如 Webpack、Babel 等,因為 CRA 它是一個封閉的黑盒,不允許開發者直接定製,但有時候我們需要對配置做一些修改,比如這裡需要配置 antd 的按需引用。
  • customize-cra:是 CRA 在釋出 2.0 之後出來的一個輔助 react-app-rewired 更方便定製 CRA 的 Webpack 配置的一個庫,它提供了一些開箱即用的 API。
  • babel-plugin-import:是配置可供開發者按需引用 antd 元件的一個 Babel 外掛
  • less 和 less-loader:是我們用於定製化 antd 的主題需要的 Webpack loader,因為 antd 使用 less 作為樣式化語言。


最後我們安裝一個在 Ant Design 4.0 拆分出去的 icons 包,可以用來按需引用 icons,進一步減少最後的打包體積,繼續在命令列執行如下命令:

$ npm install @ant-design/icons
複製程式碼


大功告成!現在我們所有的依賴以及安裝完成。接下來就需要改寫一下 CRA 之前通過 react-scripts  跑開發構建的流程,用我們安裝的 react-app-rewired  指令碼來替換它,當安裝完了所以依賴,以及用react-app-rewired   替換 react-scripts  之後,我們的 package.json  檔案應該是下面的樣子:

// ...
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ant-design/icons": "^4.0.2",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "@types/jest": "^24.0.0",
    "@types/node": "^12.0.0",
    "@types/react": "^16.9.0",
    "@types/react-dom": "^16.9.0",
    "antd": "^4.0.0",
    "babel-plugin-import": "^1.13.0",
    "customize-cra": "^0.9.1",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "react": "^16.13.0",
    "react-app-rewired": "^2.1.5",
    "react-dom": "^16.13.0",
    "react-scripts": "3.4.0",
    "typescript": "~3.7.2"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
  // ...
複製程式碼

修改配置


安裝完依賴之後,我們要確保對應改寫 CRA 流程的配置生效,我們需要根據 react-app-rewired 的文件說明在根目錄下建立 config-overrides.js 檔案,並在其中編寫如下的內容:

const { override, fixBabelImports, addLessLoader } = require("customize-cra");
const darkThemeVars = require("antd/dist/dark-theme");

module.exports = override(
  fixBabelImports("import", {
    libraryName: "antd",
    libraryDirectory: "es",
    style: true
  }),
  addLessLoader({
    javascriptEnabled: true,
    modifyVars: {
      hack: `true;@import "${require.resolve(
        "antd/lib/style/color/colorPalette.less"
      )}";`,
      ...darkThemeVars,
      "@primary-color": "#02b875"
    }
  })
);
複製程式碼


可以看到,上面的程式碼主要是匯出一個用於修改 Webpack 配置的物件,使用 override API,接收兩個修改配置的函式呼叫,fixBabelImports 用於配置 antd 的按需引用,addLessLoader 用於配置 antd 的主題,這裡我們使用了 Ant Design 4.0 新帶來的 Dark Mode(暗色模式),然後配置了主題色為圖雀社群的主題色:#02b875 ,代表希望的綠色。?

自此,我們就引入了 antd 元件庫,並進行了按需配置使用以及配置主題色和使用了 Ant Design 最新的暗色主題 -- Dark Mode。

編寫初始程式碼

準備邏輯部分


接下來,我們將使用 antd 幫助我們快速的編寫一下我們即將實現的待辦事項的介面,開啟 src/App.tsx ,對其中的程式碼做出對應的修改如下:

import React, { useState, useRef } from "react";
import {
  List,
  Avatar,
  Button,
  Typography,
  Form,
  Input,
  Select,
  DatePicker,
  Menu,
  Dropdown,
  Tabs
} from "antd";
import { DownOutlined } from "@ant-design/icons";

import "./App.css";
import logo from "./logo.svg";

const { Title } = Typography;
const { Option } = Select;
const { TabPane } = Tabs;

const todoListData = [
  {
    content: "圖雀社群:匯聚精彩的免費實戰教程",
    user: "mRcfps",
    time: "2020年3月2日 19:34",
    isCompleted: false
  },
  {
    content: "圖雀社群:匯聚精彩的免費實戰教程",
    user: "pftom",
    time: "2020年3月2日 19:34",
    isCompleted: false
  },
  {
    content: "圖雀社群:匯聚精彩的免費實戰教程",
    user: "Holy",
    time: "2020年3月2日 19:34",
    isCompleted: false
  },
  {
    content: "圖雀社群:匯聚精彩的免費實戰教程",
    user: "crxk",
    time: "2020年3月2日 19:34",
    isCompleted: false
  },
  {
    content: "圖雀社群:匯聚精彩的免費實戰教程",
    user: "Pony",
    time: "2020年3月2日 19:34",
    isCompleted: false
  }
];

const userList = [
  {
    id: "666666666",
    name: "圖雀社群",
    avatar: "https://avatars0.githubusercontent.com/u/39240800?s=60&v=4"
  },
  {
    id: "23410977",
    name: "mRcfps",
    avatar: "https://avatars0.githubusercontent.com/u/23410977?s=96&v=4"
  },
  {
    id: "25455350",
    name: "crxk",
    avatar: "https://avatars1.githubusercontent.com/u/25455350?s=96&v=4"
  },
  {
    id: "23410977",
    name: "pftom",
    avatar: "https://avatars0.githubusercontent.com/u/23410977?s=96&v=4"
  },
  {
    id: "58352313",
    name: "holy",
    avatar: "https://avatars0.githubusercontent.com/u/58352313?s=96&v=4"
  }
];

const menu = (
  <Menu>
    <Menu.Item>完成</Menu.Item>
    <Menu.Item>刪除</Menu.Item>
  </Menu>
);

const TodoInput = ({ value = {} }) => {
  return (
    <div className="todoInput">
      <Input type="text" placeholder="輸入待辦事項內容" />
      <Select style={{ width: 80 }} size="small" defaultValue="666666666">
        {userList.map(user => (
          <Option value={user.id}>{user.name}</Option>
        ))}
      </Select>
      <DatePicker
        size="small"
        style={{ marginLeft: "16px", marginRight: "16px" }}
      />
    </div>
  );
};

function TodoList() {
  return (
    <List
      className="demo-loadmore-list"
      itemLayout="horizontal"
      dataSource={todoListData}
      renderItem={item => (
        <List.Item
          actions={[
            <Dropdown overlay={menu}>
              <a key="list-loadmore-more">
                操作 <DownOutlined />
              </a>
            </Dropdown>
          ]}
        >
          <List.Item.Meta
            avatar={
              <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
            }
            title={<a href="https://ant.design">{item.user}</a>}
            description={item.time}
          />
          <div>{item.content}</div>
        </List.Item>
      )}
    />
  );
}

function App() {
  const callback = () => {};

  const onFinish = () => {};
  const ref = useRef(null);

  return (
    <div className="App" ref={ref}>
      <div className="container header">
        <img src={logo} alt="" />
        <Title level={3}>圖雀社群:匯聚精彩的免費實戰教程</Title>
      </div>
      <div className="container">
        <Form onFinish={onFinish}>
          <Form.Item name="todo">
            <TodoInput />
          </Form.Item>
        </Form>
      </div>
      <div className="container">
        <Tabs onChange={callback} type="card">
          <TabPane tab="所有" key="1">
            <TodoList />
          </TabPane>
          <TabPane tab="進行中" key="2">
            <TodoList />
          </TabPane>
          <TabPane tab="已完成" key="3">
            <TodoList />
          </TabPane>
        </Tabs>
      </div>
    </div>
  );
}
 // ...
複製程式碼


上面的程式碼主要就是一系列初始資料的準備,antd 元件的使用,編寫起來的大致輪廓,還沒有涉及到任何的 TS 語法,但這個是我們開始專案的基礎,讀者只需要進行簡單的複製放進現有的 typescript-tea 專案中對應的 src/App.tsx  中即可。

準備樣式部分


準備了邏輯程式碼之後,為了讓我們最後的待辦事項在樣式上更美觀一點,也利於我們講解時的操作,我們需要給專案加一點樣式,開啟 src/App.css 對其中的程式碼做出對應的修改如下:

.App {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 60px;
}

.container {
  width: 600px;
}

.header {
  text-align: center;
  margin-bottom: 56px;
}

.header img {
  width: 160px;
  height: 160px;
  margin-bottom: 24px;
}

.todoInput {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 40px;
  border: 1px solid #434343;
}

.todoInput input {
  border: none;
}
複製程式碼


這個時候如果你的伺服器還在執行,那麼你應該可以看到如下效果:

image.png


好了!所有的準備工作已經就緒,在開始下一節真正的 TS 學習之前,我們先來回顧一下我們在這個小節中所完成的工作:

  • 使用 CRA 的 TypeScript 指令碼初始化了一個 TS 版的 React 專案
  • 安裝了 antd 元件庫,並使用 react-app-rewired 替換預設的 react-scripts 來完成對 CRA 的 Webpack 配置進行修改,以是我們可以獲得 antd 元件的按需引用和主題定製的功能
  • 準備了初始待辦事項程式碼的邏輯部分和樣式部分


我們在前面鋪墊了大量的 TypeScript 的優點以及花了不少筆墨來準備初始程式碼,想必讀到這裡的讀者們可能已經等不及要馬上見識一下 TS 的廬山真面目了吧!馬上就來啦!

想要學習更多精彩的實戰技術教程?來圖雀社群逛逛吧。

本文所涉及的原始碼都放在了 Github  或者 Gitee 上,如果您覺得我們寫得還不錯,希望您能給❤️這篇文章點贊GithubGitee 倉庫加星❤️哦~

型別即正義:TypeScript 從入門到實踐(序章)

相關文章