以前看了一下 TypeScript 的知識,可是一直沒有上手,最近開始結合 React 和 TypeScript 一塊兒嘗試了一下,感覺仍是很好的,因此寫一下筆記。css
環境配置沒有參考其餘東西,就是看了下 Webpack 和 TypeScript 的官方文檔,使用 Webpack 進行構建仍是比較簡單的。html
建立一個項目目錄,而後切換當前目錄到項目目錄下:node
$ mkdir tsc && cd ./tsc
而後使用 npm 初始化項目:react
$ npm init -y
而後建立一些項目文件:webpack
$ mkdir build src $ touch build/webpack.base.conf.js build/webpack.dev.conf.js build/webpack.prod.conf.js index.html src/index.tsx tsconfig.json
接下來,就能夠安裝一些依賴了:es6
$ npm i webpack webpack-cli webpack-merge webpack-dev-server -D $ npm i html-webpack-plugin clean-webpack-plugin typescript ts-loader style-loader css-loader @types/react @types/react-dom -D $ npm i react react-dom -S
能夠注意到咱們沒有安裝 babel 轉譯器,若是咱們只寫 .ts
或者 .tsx
文件,能夠不安裝 babel。若是要轉譯處理 .js
文件的話,仍是要使用到 babel。web
咱們先寫基礎配置:typescript
webpack.base.conf.js
****npm
const path = require('path'); const htmlWebpackPlugin = require('html-webpack-plugin'); const cleanWebpackPlugin = require('clean-webpack-plugin'); module.exports = { entry: path.resolve(__dirname, '../src/index.tsx'), output: { filename: '[name].[hash].js' }, resolve: { extensions: ['*', '.js', '.json', '.ts', '.tsx'] }, module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }, plugins: [ new htmlWebpackPlugin({ inject: true, template: path.resolve(__dirname, '../index.html') }), new cleanWebpackPlugin(['dist']) ] };
而後能夠構造開發環境下的配置文件:編程
webpack.dev.conf.js
****
const merge = require('webpack-merge'); const path = require('path'); const baseConfig = require('./webpack.base.conf'); module.exports = merge(baseConfig, { mode: 'development', devtool: 'source-map', devServer: { port: 9999, open: true, contentBase: path.resolve(__dirname, '../dist') } });
而後添加 npm 腳本到 package.json
中:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --config ./build/webpack.dev.conf.js" }
而後添加咱們的 ts 配置到 tsconfig.json
:
{ "compilerOptions": { "outDir": "./dist/", // 打包輸出目錄 "noImplicitAny": true, // 默認必須爲變量指定類型 "module": "es6", // 使用 ESM 模塊化方案 "target": "es5", // 代碼編譯成 ES 5 "jsx": "react", // 開啓 JSX,使用 react 方式編譯,若是要使用 babel 編譯,那就將 jsx 設置爲 ‘preserve’ "allowJs": true, // 容許編譯 js 代碼 "sourceMap": true, // 編譯後同時產出 map 文件 "removeComments": true // 移除註釋 } }
更多的配置項解釋,參考:翻譯 | 開始使用 TypeScript 和 React。
寫完了之後咱們就能夠添加內容到咱們的開發文件中了:
index.html
****
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="root"></div> </body> </html>
src/index.tsx
****
import * as React from 'react'; import * as ReactDOM from 'react-dom'; ReactDOM.render( <h1>Hello TSX!</h1>, document.getElementById('root') as HTMLElement );
能夠注意到引入 React 和 ReactDOM 的方式和以前有一些不一樣。
另外因爲 TypeScript 的強制轉換符 <>
和 JSX 的元素相沖突,因此使用 as
做爲強制轉換符。
運行 npm run dev
,能夠查看效果。
使用 TypeScript 之後,項目配置要稍微簡單一點。配置好開發環境之後,就能夠寫代碼啦!
我以一個 Header 組件爲例,效果以下:
新建一個 Header.tsx
文件和一個 Header.css
文件到 src/components
下。
因爲頭部欄的標題文字應該是能夠修改的,而後右邊的 menu 應該是能夠自定義的,因此這些數據應該均可以經過 props 傳入咱們的 Header 組件。
寫咱們的 Header 組件:
// Header.tsx // 引入 React import * as React from 'react'; // 引入咱們的組件樣式 import './Header.css'; // 定義的接口,用於規範 Header 組件的 props,向外界公開, // 便於在其餘組件中引用時實現這個接口,減小錯誤 export interface HeaderProps { title: string; // 必須給定 title,一個 string 類型的值 menus?: MenuItemProps[]; // menus 是可選屬性,是一個符合 MenuItemProps 接口規範的對象的數組 height?: string; // 問號都表明可選項 bgColor?: string; } // 這個接口定義了 MenuItem 組件的 props 規範,同時也定義了 // HeaderProps 中 menus 數組的元素的規範 interface MenuItemProps { name: string; // 給定 menu 的名稱 href: string; // 給定 menu 要跳轉的連接 } // 定義了 Header 組件的 state 的規範 interface HeaderState { isVisible: boolean // 表明 Header 組件是否可見 } // Header 組件 // 注意 React.Component 後面的泛型,就是咱們上方定義的接口,它們分別制定了組件的 props 和 state 的規範 class Header extends React.Component<HeaderProps, HeaderState> { // 指定組件實例的 state,必須符合 HeaderState 的規範 state = { isVisible: true } render() { const { title, menus = [], height = '50px', bgColor = 'lightblue' } = this.props; // 從 props 獲取值,其中可選項都有默認值 const style = { height, backgroundColor: bgColor }; // 構造 Header 內聯樣式 return this.state.isVisible ? <div style={style} className="header"> <span>{title}</span> <div className="header-menus"> { menus.map(item => <MenuItem {...item}/>) } </div> </div> : null; } } // MenuItem 組件 // state 的規範是一個 object,未指定具體接口類型 class MenuItem extends React.Component<MenuItemProps, object> { render() { const { name, href } = this.props; return <a className="header-menu-item" href={href} key={href}> {name} </a> } } // 最後向外部暴露 Header 組件 export default Header;
能夠看到 TypeScript 結合 React 其實很好用,尤爲在規範 props 的時候很好用,可以避免不少編程時候的錯誤。而 IDE 的提示可以更加地方便咱們開發。寫起來何止舒服,簡直舒服啊~
而後在 Header.css
寫一下咱們的樣式:
html, body, div { margin: 0; padding: 0; font-size: 16px; } .header { font-size: 1.5rem; line-height: 1rem; padding: 1rem; box-sizing: border-box; position: relative; } .header-menus { position: absolute; right: 1rem; top: 50%; transform: translateY(-50%); } .header-menu-item { margin: 0 .5rem; }
這裏僅僅是作個示例,排版沒有在乎太多的通用性,你們看看就好~
而後咱們就能夠在 index.tsx
中使用咱們的 Header 組件了:
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Header, { HeaderProps } from './components/Header'; // 引入接口規範和組件 // 構造 Header 組件的 props,必須符合 HeaderProps 接口規範。 // 在寫的過程當中 IDE 也能給咱們不少的提示,方便了開發 const headerProps: HeaderProps = { title: 'Hello TSX!', menus: [{ name: 'menu1', href: 'https://www.zhongdeming.fun' }, { name: 'menu2', href: 'https://www.baidu.com' }], bgColor: 'lightyellow' }; ReactDOM.render( <Header {...headerProps}/>, document.getElementById('root') as HTMLElement );
這樣一個組件就寫完了,能夠感覺到 TypeScript 確實可以加速咱們的開發,減小開發中的錯誤。
下面是一些利用 TypeScript 開發的時候 IDE 給出的提示的截圖: