關於 TypeScript
早在去年(2017),TypeScript 贏來了它的爆發式增長。時至今日,隨著 JavaScript 的程式碼數量越來越龐大,越來越多的開發者意識到 JavaScript 在構建大型專案時的不足之處。JavaScript 是動態型別的,只能在 runtime 時進行型別檢查;同時它也給重構大型專案帶來了的困擾,在一定程度上,它是不「易讀」的。而 TypeScript 能夠很好的解決上述問題。
TypeScript 最早是在 2012 年十月份由微軟開源在 GitHub 上,它是 JavaScript 的一個超集,除了能讓我們使用 ES Future 的各種語法外,還提供如 Enum、Tuple、Generics 等的新語法。當然,向 JavaScript 提供一個可選的靜態型別是一個最重要的變化點了。
在接下來,我將簡單的闡述為什麼靜態型別對大型專案是友好的,以及對 Function type 的一次實踐寫法。
靜態型別對大型專案是友好的
儘早檢查錯誤
如前文所提及的,JavaScript 是動態型別的語言,它沒有 Type System,只能在 runtime 時進行型別檢查,如果你不是足夠的小心,難免會出現下列情況:
在這個簡單的例子裡,我們認為 someMethod
的引數一個陣列,可是實際情況並不是,它是一個數字。理所當然,它報錯了。
改為 TypeScript 加上簡單的型別推斷時:
可見,它在編譯前就已經給出了錯誤的提示。
閱讀程式碼友好
或許你也剛好認為「程式碼是給人讀的,只是順便在機器上跑一下」,我相信你會在 Function、Class、Modules 或者其他地方加上 JSDoc。不同於 JSDoc,TypeScript 提供的型別宣告和模組介面形成了文件的形狀,提供程式的行為提示,並在編譯時會校驗程式的正確性。
改動下上個例子:
當然,對大型專案來說,這可能要複雜的多。儘早的發現錯誤,對閱讀程式碼更友好,或多或少能讓我們在重構專案時更方便。
Function type
先從一個簡單的 Function type 入手:
(arg: number) => string
複製程式碼
在上面的一個 Function type 中,它接收一個數字型別的引數,並返回一個字串型別。
現在來使用它:
const func: (arg: number) => string = String // 在這裡 String 是一個方法
複製程式碼
在實際應用中,並不會這麼用,因為 TypeScript 知道 String 的型別,並能準確的推匯出 func 的型別。
一個更加實際的例子:
function someMethods (callback: (arg: number) => string) {
return callback(321)
}
複製程式碼
現在,你可以使用這個定義的方法,但是傳入的引數必須符合 (arg: number) => string
,比如你可以使用 someMethods(String)
而不能使用 someMethods(Number)
。
加上函式返回:
function someMethod (
callback: (num: number) => string
): string {
const num = 123
return String(num)
}
複製程式碼
有些時候,並不想傳 callback
:
function someMethod (
callback?: (num: number) => string
): string {
const num = 123
if (callback) {
return callback(123)
}
return String(num)
}
複製程式碼
或者,我們希望 callback 是必須的,如果你不想提供一個函式,你必須顯式的提供一個 null:
function someMethod (
callback: null | ((num: number) => string)
): string {
const num = 123
if (callback) {
return callback(123)
}
return String(num)
}
複製程式碼
定義成一個 type:
type SomeMethod = (callback?: ((num: number) => string)) => string
複製程式碼
在這個 type 裡,我們定義了一個 someMethod 方法,它有一個可選引數 callback,同時規定這個 callback 有且僅有一個型別為 number 的引數。
接下來,我們擴充套件這個 type ,使用泛型(你可以簡單的理解泛型是一種資料型別)並改變它的 callback:
type SomeMethod<T> = (
callback: (value: T, index: number, array: T[]) => T
) => T
複製程式碼
給泛型加一個預設值,並加個可選引數:
type SomeMethod<T = string> = (
callback: (value: T, index: number, array: T[]) => T,
thisArg?: T
) => T
複製程式碼
至此,一個簡單的 Function type 已經完成了。
事實上,Function types 還有各種有趣玩法:
type SomeMethod<T = string> = (
callback: (...arg: (T[] | T)[]) => T[]
// ...
) => T
複製程式碼
// 多泛型,並帶有約束時
type OthemMethod <T, P extends keyof T> = (
obj: T,
key: P
) => T[P]
複製程式碼
實際上 TypeScript 2.4 版本以後,可以對函式呼叫的返回值進行判斷
function arrayMap<T, U>(
f: (x: T) => U
): (a: T[]) => U[] {
return a => a.map(f)
}
const lengths: (a: string[]) => number[] = arrayMap(a => a.length)
console.log(lengths(['123', '1', '1'])) // 3, 1, 1
複製程式碼
以及更多有趣的寫法,這裡不再介紹了。
參考:
- https://www.typescriptlang.org/docs/home.html
- https://zhuanlan.zhihu.com/p/24267683
- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html
- https://juejin.im/post/59c46bc86fb9a00a4636f939