React項目重構到TS+React版本

儲備知識

基本數據類型

布爾 數字javascript

元祖css

const author:[string, string] = ['mx', '大風']
複製代碼

枚舉, 好比應用於訂單狀態html

enum Order {
  finish = '訂單完成',
  deleted = '訂單刪除',
  send = '訂單已發出'
}
複製代碼

any 放棄類型檢查html5

  • ? 無關緊要
function users(name?:string) {
  console.log(name)
}
function users(age:number = 18, name?:string) {
  console.log(name)
}
function users(...numbers: number[]) {
  console.log(name)
}
複製代碼

class

public private protectedjava

public name: string;  //類裏面 子類 其它任何地方外邊均可以訪問
    protected age: number; //類裏面 子類 均可以訪問,其它任何地方不能訪問
    private money: number; //類裏面能夠訪問, 子類和其它任何地方都不能夠訪問
複製代碼

聲明文件

安裝 TypeScript 時,會順帶安裝 lib.d.ts 聲明文件。此文件包含了 JavaScript 運行時以及 DOM 中存在各類常見的環境聲明node

對於項目中一些全局可用的變量或者接口,能夠考慮建立一個globals.d.tsreact

globals.d.ts 能夠看作是 lib.d.ts 的擴充webpack

接口

TypeScript的核心原則之一是對值所具備的結構進行類型檢查git

基本使用

在TypeScript裏,接口的做用就是爲這些類型命名和爲你的代碼或第三方代碼定義契約。es6

定義屬性

interface props {
  readonly name: string
  habit? : string
}
複製代碼

函數 && 接口

定義一個函數所需的形狀

  • 函數聲明
interface fnBox {
  (len:number, cont: number): number[]    
}
let pushAry:fnBox
pushAry = function (len: number, cont: number) {
  return new Array(len).fill(cont)    
}
複製代碼

若是這裏故意寫錯cont的類型,會有什麼提示

inetrface

能夠定義無返回值的函數

interface props {
  once(): void 
  twice: () => void 
}
複製代碼
  • 函數表達式

咱們也可使用函數表達式去書寫函數

let sing = () => {-- do something --}
複製代碼

函數表達式添加約束能夠寫爲

let sing = (singer: string): boolean => {-- do something --}
複製代碼

可是這種只是對等號右側的匿名函數進行了類型定義,而等號左邊的 sing,是經過賦值操做進行類型推論而推斷出來的

手動給 sing 添加類型,則應該是這樣:

let sing: (singer: string) => boolean = (singer: string): boolean => { -- do something-- }
複製代碼

類 && 接口

implements 可使類 具備接口的屬性功能

interface int2 {
  once(): void,
  touchMore: (count: number) => void
}

class Btn implements int2 {
  once () {
    console.log('once')
  }
  touchMore (count: number) {
    console.log('touchMore')
  }
}

const btns = new Btn
btns.once()
btns.touchMore(9)
複製代碼

class

配置 tsconfig.json

1 使用webpack搭建項目的時候,有配置alias參數

'utils': path.resolve(__dirname, '../utils')
複製代碼

這樣在組件中引入的時候,文件路徑能夠簡化

import { log } from 'utils/statistics'
複製代碼

不過在使用ts以後,會發現組件中有警告信息,表示找不到此模塊

就須要另外在tsconfig中添加配置參數

"baseUrl": "./",
    "paths": {
      "components": ["./components/*"],
      "utils": ["./utils/*"],
    }
複製代碼

2 other

noEmitOnError: true
複製代碼

當編譯出錯,則不輸出編譯後的文件

全局變量 window

在訪問頁面的時候,server會反饋一些基本的用戶信息,好比用戶名,設備版本號等,將這些所有掛載在CONFIG變量中了

<script type="text/javascript">
  window.CONFIG = JSON.parse(decodeURIComponent('{{feConfig}}'))
</script>
const {uid, version} = window.CONFIG // 而後在組件中能夠直接獲取
複製代碼

可是在加入TS以後,會提示window中不存在屬性CONFIG

window

TS不容許獲取,設置沒有聲明過的屬性,因此這裏報錯了

處理方案

1 全局擴展

在模塊內部添加聲明到全局做用域

在入口文件index.tsx中 添加聲明

declare global {
   interface Window { CONFIG: any }
 }
 const {uid} = window.CONFIG
複製代碼

2 使用類型斷言

const { apk } = (window as any).CONFIG
複製代碼

3 添加 globals.d.ts 聲明文件

interface Window {
  CONFIG: any
}
複製代碼

泛型

import * as React from 'react'

class App extends React.Component<props, state>{
    -- do something --
}
複製代碼

定義

泛型是指在定義函數、接口或類的時候,不預先指定具體的類型,而在使用的時候再指定類型的一種特性

好比寫一個根據指定內容填充到指定長度的數組生成函數 getAry

function getAry (len: number, cont: string | number): string[] | number[] {
  return new Array(len).fill(cont)
}
複製代碼

參數

參數 含義 類型
len 指定長度 number
cont 指定內容 string 或 number (使用聯合類型處理)

因爲不肯定參數cont的輸入類型,因此返回值使用了聯合類型處理

這種須要 返回值類型和輸入參數類型保持一致的狀況,可使用泛型T來處理

泛型是類型變量,一種用來表示類型的特殊變量

  • 使用方式

在函數名後添加<>

function createFn<T>
function createFn<string> // 明確指定 T 是 string 類型的
複製代碼

其實泛型函數的類型與非泛型函數的類型沒什麼不一樣,只是多了一個類型參數在最前面

  • 能夠指定默認類型

TypeScript 2.3 之後,咱們能夠爲泛型中的類型參數指定默認類型。當使用泛型時沒有在代碼中直接指定類型參數,從實際值參數中也沒法推測出時,這個默認類型就會起做用

function beConfusion<T = boolean> (name: string, isDone: boolean) {...}
複製代碼

泛型接口

將上面那個函數使用接口來定義

interface dealFn {
  <T>(len: number, cont: T): T[]    
}
let getAry: dealFn
getAry = function <T> (len: number, cont: T): T[] {
 --do something--    
}
複製代碼

泛型類

泛型類使用<>括起泛型類型,跟在類名後面

class DealAry<T> {
  value: T
  constructor (value: T) {
    this.value = value
  }
  deal () {
    console.log(this.value)
  }
}
複製代碼

other

  • 其他的一些泛型變量

雖然能夠本身定義泛型變量結構,可是通常會使用已定義好的泛型

Promise

async taobaoGoods =  function (ids: number[]): Promise<string> {
  return new Promise <string>((reslove, reject) => {
    try{
      reslove('success')
    } catch {
      reject('failture')
    } 
  }) 
}
複製代碼
  • 能夠有多個泛型變量
class 複製代碼

React.component 類的泛型變量

打開 node_modules/@types/react 能夠看到 component 類

component

簡單歸納就是

class Component<P = {} , S = {} > {
  -- other --
  readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>
  state: Readonly<S>
  -- other --
}
複製代碼

能夠看到 props 和 state 兩個對象都是隻讀的

因此咱們在寫React組件的時候,要調整爲

interface BannerProps {
  showUpdate(): void,
  clickOnce: (type: string, id: number) => void
}

interface BannerState {
  once: boolean
}

export default class Banner extends React.Component<BannerProps, BannerState> {
  --do something--
} 

複製代碼

類型斷言

獲取一個元素的某個屬性

componentDidMount () {
  const target = this.refs.img
  if (target.getAttribute('src') != newSrc) { -- do something-- }   
}
複製代碼

ts提示有錯誤

HTMLElement

這是由於TS推斷target 還不具有getAttribute 屬性

TypeScript 容許你覆蓋它的推斷,而且能以你任何你想要的方式分析它,這種機制,被稱爲「類型斷言」

TypeScript 類型斷言用來告訴編譯器你比它更瞭解這個類型,而且它不該該再發出錯誤

<類型>值 或者 值 as 類型
複製代碼

*** 在jsx中必須使用 第二種方式去處理 ***

在不肯定類型的時候就訪問其中一個類型的屬性或方法,可使用類型斷言

function getType (arg: string | boolean): boolean {
  if ( arg.length ) return true
  return false
}
複製代碼

這種其實會報錯的,若是輸入是布爾值,則沒有length

加入類型斷言

function getType (arg: string | boolean): boolean {
  if ( (arg as string).length  ) return true
  // if ( (<string>arg).length ) return true
  return false
}
複製代碼

斷言成一個聯合類型中不存在的類型是不容許的

if ( (arg as array).length  ) return true // 報錯
複製代碼

因此上面組件裏 須要調整爲

const target = this.refs.img as HTMLElement 
複製代碼

內置對象

JavaScript 中有不少內置對象,能夠直接在 TypeScript 中當作定義好了的類型

const isEnd:Boolean = new Boolean(false)

interface createEle {
  createElement(tagName: "div"): HTMLDivElement    
}

複製代碼

設置組件屬性

interface videoProps {
    poster?: string
}

class Video extends Component<videoProps> {
    static defaultProps = {
        poster: ''
    }
}
複製代碼

webpack 調整爲 ts 格式

新項目中將webpack部分調整爲ts處理

參考文章,官網地址

儲備知識

ts-node 能夠直接運行.ts文件 ts版本使用方式見官網

tsconfig

tsconfig.webpack.json中的配置直接按照官網中去寫的

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "esModuleInterop": true
  }
}
複製代碼

tsconfig

這裏配置的是es5 將其調整爲es6便可

或者使用 webpack-merge 進行模塊合併

const config: Configuration = merge(commonPlugin, {...})

複製代碼

未解決的問題

  • 關於 import 模塊

項目中保留了一份 webpack.common.js的文件,發如今 import 模塊的時候 會先找到 這個.js的 而不是 .ts

import commonPlugin from './webpack.common'
複製代碼

ts.config 中有一個 allowJs 參數 若是設置爲TRUE 則能夠引入js文件 可是這個默認的是FALSE 因此應該不會有引入 js文件

因此很奇怪 - 文檔

暫時將js文件名修改了

掉坑記錄

::寫法

<Banner once={::this.update} />
複製代碼

這個主要是藉助了bable 的 transform-function-bind 雙冒號實現綁定

TS不支持這種寫法 能夠調整爲

<Banner once={() => this.update} />
<Channel clickOnce={this.clickOnce.bind(this)} /> 複製代碼

issue

es6的新語法

組件中有使用

const result = Object.assign({}, params, info)
複製代碼

處理方案

1 藉助lodash

安裝lodash.assign和@types/lodash

2 更換複製對象方案

3 調整tsconfig配置文件

以前

target: es5
複製代碼

調整爲

target: es6
複製代碼

注意可能須要重啓 VScode 才能夠生效

3 img 元素屬性

在獲取img元素的src屬性的時候,是這麼寫的

(target as HTMLElement).getAttribute('src')
複製代碼

而後在直接設置src值的時候

(item as HTMLElement).src = itemSrc
複製代碼

這樣就會報錯,須要調整爲

(item as HTMLImageElement).src = itemSrc
複製代碼

getAttribute 屬於 HTMLElement 屬性,而 src 屬於 HTMLImageElement 的屬性

補充一下 element HTMLElement node 的屬性方法

element對象

htmlelement對象

node對象

後續還在調整中,繼續更新掉坑記錄部分

相關文章
相關標籤/搜索