若是你:react
看到如下代碼有沒有很疑惑?typescript
function makePair< F extends number | string, S extends boolean | F >()
Java是和typescript同樣支持泛型的,當我在大學開始學習Java的時候,我仍是一個菜鳥碼農,遇到難點(好比泛型)就直接跳過,能學多少學多少,回寢室就LOL開黑。直到大學畢業我依舊沒有理解泛型的概念閉包
可能你和我同樣以爲泛型很難,下面我會分享個人理解,但願對你有所幫助。函數
makeState()
這個函數首先,我寫了makeState這個函數,咱們會用這個函數來討論泛型學習
function makeState() { let state: number function getState() { return state } function setState(x: number) { state = x } return { getState, setState } }
當你運行這個函數,咱們會獲得getState()
和 setState()
這兩個函數。code
讓咱們來試一下,下面這段代碼會打印出什麼ip
const { getState, setState } = makeState() setState(1) console.log(getState()) setState(2) console.log(getState())
1
2
會打印出1和2,沒那麼難對吧?ci
Note: 若是你正在使用react,你可能會發覺,makeState()
和鉤子函數useState()
很像。這裏也涉及到了 閉包和ES6的 解構賦值
咱們把剛纔給setState
的入參1
和2
替換成字符串'foo'
會輸出什麼呢?字符串
const { getState, setState } = makeState() setState('foo') console.log(getState())
Argument of type '"foo"' is not assignable to parameter of type 'number'.
會編譯失敗,由於setState()
須要的參數類型是number
get
咱們能夠用如下方法解決這個問題
function makeState() { // Change to string let state: string function getState() { return state } // Accepts a string function setState(x: string) { state = x } return { getState, setState } }
const { getState, setState } = makeState() setState('foo') console.log(getState())
foo
咱們能不能修改makeState()
這個函數,來輸出兩個不一樣類型的state,好比一個是字符串,一個是數字。
如下代碼簡略得表示我想表達的意思:
// One that only allows numbers, and… const numState = makeState() numState.setState(1) console.log(numState.getState()) // 1 // The other that only allows strings. const strState = makeState() strState.setState('foo') console.log(strState.getState()) // foo
要達到以上效果,咱們可能須要建立兩個內部不同的makeState()
,一個state
的類型是數字,一個是字符串。
怎麼用才能只寫一個來實現呢?
這是咱們的第一個嘗試:
function makeState() { let state: number | string function getState() { return state } function setState(x: number | string) { state = x } return { getState, setState } }
const numAndStrState = makeState() //數字 numAndStrState.setState(1) console.log(numAndStrState.getState()) //字符串 numAndStrState.setState('foo') console.log(numAndStrState.getState())
1
foo
結果看上去咱們貌似成功了,可是這並非我真實想要的,咱們真正要實現的是只能輸出數字state
和只能輸出字符串state
。numAndStrState
是既能輸出數字類型,又能輸出字符串類型
接下來咱們的泛型要登場了:
function makeState<S>() { let state: S function getState() { return state } function setState(x: S) { state = x } return { getState, setState } }
makeState()
被定義成 makeState<S>()
,你能夠把<S>
看成函數參數,但它傳入的不是值,而是類型。
好比你能夠傳入數字類型:
makeState<number>()
在makeSate()
這個函數內部state
會變成數字類型
let state: S // <- number function setState(x: S /* <- number */) { state = x }
這樣就實現了只能輸出數字state
// Creates a number-only state const numState = makeState<number>() numState.setState(1) console.log(numState.getState()) // numState.setState('foo') 輸入字符串foo會報錯
同理咱們也能夠實現只能輸出字符串state
// Creates a string-only state const strState = makeState<string>() strState.setState('foo') console.log(strState.getState()) // strState.setState(1) 輸入數字1會報錯
Note: 咱們把
makeState<S>()
稱做泛型函數,就是一個普通的函數支持類型參數的傳入你可能會疑惑爲何類型參數是
S
, 其實隨便什麼均可以,可是一般來講咱們會用一個變量的第一個字母的大寫來表明這個變量的類型:
T
(for「T」ype)E
(for「E」lement)K
(for「K」ey)V
(for「V」alue)
目前,在咱們改進下的makeState()
實現了只能輸出數字state
和只能輸出字符串state
。可是它也能實現輸出布爾值。
// Creates a boolean-only state const boolState = makeState<boolean>() boolState.setState(true) console.log(boolState.getState())
問題:那麼咱們要如何限制它就只能輸入輸出number
和string
類型呢?
方法:聲明makeState()
這個函數時,把類型參數<S>
變爲<S extends number | string>
,這樣就只能輸入number
或者string
類型了
function makeState<S extends number | string>() { let state: S function getState() { return state } function setState(x: S) { state = x } return { getState, setState } } // 若是我傳入boolean類型 const boolState = makeState<boolean>()
Type 'boolean' does not satisfy the constraint 'string | number'.
如今每次調用makeState()
時,咱們能夠任意傳入<number>
或<string>
類型,那怎麼設置一個默認類型呢?
好比讓下面兩個語句起到相同的做用:
const numState1 = makeState() const numState2 = makeState<number>()
其實和給函數參數設置默認值同樣:
function makeState<S extends number | string = number>()
這樣,變量state
默認類型就是number
了
const numState = makeState() numState.setState(1) console.log(numState.getState())
1
泛型其實能夠看成普通函數在聲明時的一個參數,這個參數表明類型。
咱們能夠給函數值參數設置默認值,
也能夠經過typescipt的泛型給函數類型參數設置默認值。
function regularFunc(x = 2) regularFunc()
function genericFunc<T = number>() genericFunc()