Typescript 4_ 那些奇怪的字(上) extends, infer, typeof
這篇中途有點難產,畢竟我好像不小心難度拉太高了,所以在思考名詞解釋的情況的時候都是有點不太合適的感覺...另外這些關鍵字詞有 extends, infer, typeof, as, in, keyof, never, unknown, void, static, get, set, readonly,前面會先介紹一部分。
在這篇中,來介紹一下會在typescript看到的關鍵字詞
extends
繼承屬性
extends
的使用上,跟前一篇&
的使用有那麼一點的類似,不過在typescript的用法更偏向於物件導向的繼承
/inheritance
的概念。
那...什麼是繼承?就請去找oop相關的書籍,這邊就不再贅述了。畢竟寫oop的前輩對於繼承的相關說明都很透徹了,就無需我再重新解釋:P
有趣的是在typescript的實作中,extends
是可以拿來做conditional type來實作的。
也就是可以利用3元表達式 a ? b : c
來對 generic type
做更進一步的屬性判定。
interface IFoo {
props: string;
}
interface IFooReturn {
result: string;
}
interface IBar {
name: string;
}
interface IBarReturn {
result: number;
}
function Sample<T>(arg: T): T extends IFoo ? IFooReturn : IBarReturn;
而 conditional type
搭配 infer
就有各種的實作產生
infer
type inference 取得function裡面的數值
就如字面上的意義來說,這個是常用來取得 function
裡面的參數值,在 typescript 內建函數 utility types
中,可以看到其實作 ReturnType
的內容。
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
有關utility types的各項函數說明,之後會再提到
另外也可以使用 infer
直接提取 Promise
的回傳值
type PromiseResolve<T> = T extends Promise<infer P> ? P : never;
let foo: PromiseResolve<Promise<string>> // 等同 let foo: string
typeof
懶人的救星
在寫js常常需要使用到 typeof
檢查型別是否是我們想要的格式,在 typescript 的 definition 裡面,也可以利用typeof
的好用屬性,讓我們快速建立型別...如果不想寫interface的話
const payload = {
gate: true,
id: 0,
name: 'test'
};
// 使用 alias type
type TPayload = typeof payload;
這樣就會自動建立payload的對應型別出來了
不僅僅是object,function也是可以直接指定出來
function Foo () {
return 'bar';
}
type TFnFoo = typeof Foo; // () => string
然後可以跟上面的 ReturnType
和 PromiseResolve
做一次組合
async function service () {
const result = await fetch(/* url */).then(res => res.json())
const map = result.map(/* do something with result */)
return map;
}
type TFoo = PromiseResolve<ReturnType<typeof service>>;
這樣我就可以先行宣告 TFoo
即 service()
回傳且經過處理的內容,而且去掉Promise
的部分。
雖然很方便,不過...還是建議勤勞點定義好interface XD
目前來說,最難的部分已經過去了,extends的conditional type
的用法,infer取出 function 中的參數,typeof 取得已經設定好value的型別。
下一篇 大概就是 as / in / keyof 上場了...吧?
留言
張貼留言