函數(shù)重載(overload)
什么是函數(shù)重載?簡單來說就是同名的函數(shù),這個概念是從 java 來的
我們來看這個需求,一個方法接受的參數(shù)有兩種情況,可能是 number,可能是 string
如果用 TS 來實現(xiàn),非常簡單
class X {
method(n: number | string) {
/* ... */
}
}
但是 java 不支持這種情況的聯(lián)合類型,但是遇到這種需求該怎么辦呢?java 的設計者當時又不想直接弄出這么個聯(lián)合類型,那干脆讓一個方法寫兩遍好了
class X {
method(n: number) {
/* ... */
}
method(n: string) {
/* ... */
}
}
于是 java 就誕生了一個新語法,一個類的方法是可以同名的,用你的參數(shù)類型和個數(shù)來判斷會具體執(zhí)行那個函數(shù)(很奇怪的語法吧~)
所以重載是為了解決 java 的一個問題
其實在很久之前大家都應該接觸過函數(shù)重載,在 JQuery 時代的 Selector 一樣
$('#div')
$(window)
$...
也許內(nèi)部使用了大量的 if else,所以說 js 不需要重載這個特性,也能做出一樣的效果
但是說回 TS,我認為只有這些情況可能需要用重載
一個創(chuàng)建日期的函數(shù),可以接受一個數(shù)量 number,也能接受具體的日期
function createData(n: number): Date
function createData(year: number, month: number, date: number): Date
// TODO: 注意:下面這里會和 java 稍微不同一點
function createData(a: number, b?: number, c?: number): Date { // TODO: 最后一個實現(xiàn)的簽名需要兼容上面所有的情況
if (a !== undefined && b !== undefined && c !== undefined) {
return new Date(a,b,c)
} else if (a !== undefined && b === undefined && c === undefined) {
return new Date(a)
} else {
throw new Error('只接受一個或三個參數(shù)')
}
}
也許也能用聯(lián)合類型?if else 實現(xiàn)出來,但是重載會更優(yōu)雅一點
但是我個人依然保持能不用就不用的態(tài)度看待它,就算遇到這種問題,為何非要用一個函數(shù)來解決,用兩個不同名稱的函數(shù)來不香么,createDataByNumber 和 createDataByYMD
其實如果你是一個庫的封裝者,像 JQuery 一樣,把函數(shù)封裝的復雜度留給自己,使用函數(shù)重載能方便使用者
但如果你是想把函數(shù)的使用權交給用戶,就應該多明明幾個函數(shù)提供用戶任意組合使用
this
在 TS 中怎么定義 this 的類型呢?
type Person {
name: string;
}
function fn(this: Person, word: string) { // TODO: 這個地方好奇 this 為什么會在參數(shù)上的人,請看我的 javascript-this 文章
console.log(this.name, word)
}
fn('hi') // TODO: 報錯
this 在參數(shù)上了,那么該如何調(diào)用呢?看下面幾種方法:
// 強行拼湊出 person.fn()
const p: Person & { fn: typeof fn } = { name: 'jack', fn }
p.fn('hi')
// fn.call()
fn.call({ name: 'jack' }, 'hi')
// fn.apply()
fn.apply({ name: 'jack' }, ['hi'])
// fn.bind()
fn.bind({ name: 'jack' })('hi')
... 與 參數(shù)
剩余參數(shù)
function sum(...x: number[]) {
return x.reduce((a,b) => a + b, 0)
}
sum(1)
sum(1,2,3,4,5)
sum(1,2,3,4,5,6,7,8,9)
展開參數(shù)
function sum(name: string, ...rest: number[]) {
fn(...rest)
// or
fn.apply(null, rest)
}
function fn(...x: number[]) {
console.log(x)
}
as const
我們知道 TS 有自動推導
let a = 'hi'
此時我們很容易看出來 a 的類型是 string
其實這樣可能會有些問題
理論上來說 a 的類型應該可能是 'hi' 或者 string
但是這個 TS 怎么知道我們這個 a 是常量(即類型為 'hi')還是 string 呢?
用 const
let a = 'hi' as const
不對啊,直接用 const 關鍵詞不就好了
const a = 'hi'
其實大多數(shù)的應用場景在對象上,因為 JS 的 const 就是殘廢
const array = [1, 'hi'] as const
參數(shù)對象的析構(gòu)
type Config = {
url: string;
method: 'GET' | 'POST' | 'PATCH';
data?: number;
}
// 使用一
function ajax({ url, method, ...data }: Config) {}
// 使用二
function ajax({ url, method, ...data }: Config = {url: '', method: 'GET'}) {}
// 使用三
function ajax({ url, method, ...data } = {url: '', method: 'GET'} as Config) {}
void
function f1(): void {
return
}
function f2(): void {
return undefined
}
function f3(): void {
}
function f4(): void {
return null // TODO: 報錯
}