iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0

比較基礎的TypeScript概念,以我能力所及,已經提的差不多了QQ

那接下來就讓我們看看要怎麼在React中加上TypeScript吧!

相信前面十幾天的文章,你已經學會/至少知道如何描述一個變數/物件的型別,我們主要沒帶到的大概就是JavaScript的class類別了。(在當今React世界中,class components已經是比較少人會使用的寫法(儘管他有其無可取代性),相對的,後來產生的Functional component逐漸成為主流,Hook的引入也使得React的門檻稍稍降低了一些,所以沒提到class應該不影響後續學習。)

接下來幾天,我們會開始在React中練習加上TypeScript,這邊建議你在本地端架一個已經有TypeScript樣板的React專案,指令如下:

> npx create-react-app my-app --template typescript
//或是
> yarn create react-app my-app --template typescript

TypeScript樣版的React安裝完畢後,我們就能看到src資料夾內,App從原本js副檔名,轉變成了tsx副檔名,接著我們就能開始使用了!

JavaScript版的React資料夾結構

TypeScript版的React資料夾結構

今天我們講個簡單的useState就好

useState

讓我們直接在App.tsx內寫點東西吧,首先我們來寫個useState
會讀到這邊的你,早就知道useState()函式內要放的是什麼了,就是個起始值,它可以是原始值,也可以是物件,甚至可以是一個callback function。

在.tsx內

import {useState} from 'react' //記得引入喔

function App(){
    const [count, setCount] = useState(0)
    
    const onClick = () => {
        setCount(prevCount=>prevCount + 1)
    }
    
      return (
    <div className="App">
      <span>{count}</span>
      <button onClick={onClick}>Hi</button>
    </div>
  )

}

從上面的程式碼來看,我們雖然沒有明確寫出count的型別,但TypeScript已經從起始值幫我們推測countnumber了,所以後續我們在我們自定義的onClick函式裡面,對每次的點擊進行+1,也是合法不會報錯的。

那我們把onClick內的setCount換成別的東西試試看

    const onClick = () => {
        setCount("no count")
    }

這時就會看到TypeScript報錯了:

類型 'string' 的引數不可指派給類型 'SetStateAction<number>' 的參數

那麼,如果我們真的需要讓count的型別,有時是數字,而有時又是字串,該怎麼做呢?就主動註記型別吧:

    const [count, setCount] = useState<string | number>(0)

    const onClick = () => {
        setCount("no count")
    }

這樣子TypeScript就不會報錯了,因為count現在已經被使用者判定為可能會是字串也可能會是數字了。

我們也能運用先前講到的型別別名,也能解決一樣的問題:

    type Count = string | number
    
    const [count, setCount] = useState<Count>(0)

    const onClick = () => {
        setCount("no count")
    }

假如起始值是個物件,後續更新變數的規則也是差不多的:

interface Count {
  value: number
}

function App() {
    //我知道寫法有點醜,但...會習慣的
  const [count, setCount] = useState<Count | null>({ value: 0 })
  const onClick = () => {
    setCount(null)
  }

  return (
    <div className="App">
      <span>{count && count.value}</span>
      <button onClick={onClick}>Hi</button>
    </div>
  )
}

在上面的程式碼中,我們將count起始值設定為一個物件{value: 0},所以TypeScript就會預設你之後的count,形狀都會是{value: number}。若我們想要在後續讓他變成null,甚至是起始值讓他為null而後續變成{value: number},就在創立前為他進行型別聯集的宣告<Count | null>,就可以了。

這邊值得注意的是,由於count可能是一個有value的物件、也可能是null,所以我們在return JSX時,必須確認countnull時,才能正確渲染count.value,若直接寫<span>{count.value}</span>,TypeScript就會噴錯!

由簡單的例子出發,我們就能知道,要是在一開始有主動去宣告型別,在後續便能避免我們自己(或同事)意外的將某變數修改為錯的型別,大大減少後續debug的時間,且在React當中,我們有很大機率會將countsetCount當做props給傳到子層去,沒有TypeScript的話,我們容易降低對變數的掌握度。建議大家可以練習看看將useState的初始值設定成更加複雜的型態(當然你也可以改成使用useReducer啦,不過這我們後面會講到),就能體會到TypeScript的優點囉。


上一篇
第20天!TypeScript的各式運算符!
下一篇
第22天!TypeScript與React的Props!
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言