[Day04] TS:如何把物件型別的所有屬性名稱取出變成 union type?試試看 keyof 吧!
前面兩天的文章中我們談到泛型(generics)的使用,以及如何透過 extends
來限制泛型可被帶入的型別。在後面的內容中,會越來越著重在如何透過 type 來產生另一個 type。
今天就來看看 keyof
的使用。
區分物件型別(type)和物件(value)
keyof
顧名思義就是把「物件型別(object type)」的 key 拿出來,但要留意的是,這裡提到的是「物件型別」,而不是真的「物件」,前者是 TypeScript 的型別,後者是 JavaScript 中的一個物件(object):
// Person 是一個 object type
type Person = {
firsName: string;
lastName: string;
};
// person 是 JavaScript 的 object (value)
const person = {
firstName: 'Aaron',
lastName: 'Chen',
};
如果不小心把真正的 object 當成 typescript 的 type 來使用的話,因為它不是型別的緣故,TypeScript 是會報錯的:
keyof operator 的使用
而這裡提到的 keyof
就只能用在「物件型別」上,使用方式非常簡單:
// Person 是一個 object type
type Person = {
firsName: string;
lastName: string;
};
type PersonKey = keyof Person;
滑鼠移到 PersonKey
上後將會看到:
實際上的意思則是 "firsName" | "lastName"
:
簡單來說,透過 keyof
operator,就可以取出物件型別的 key,並建立成一個新的 type:
搭配 & string 使用
由於「物件型別(object types)」的屬性名稱不一定是 string
,也有可能是 number
或 symbol
,因此若有需要的話,可以搭配交集(&
)的使用,也就是 & string
:
type PersonKey = keyof Person & string;
註:「物件型別」的 key 可以是
string
或number
,但 JavaScript 中「物件」的 key 只會是string
或symbol
。
這時候 TS 就會明確知道說你要取出的是型別為 string 的 object key:
小知識:any 的 keyof 是?
在 TypeScript 中,透過 keyof
則可以看到 any
的型別是 string | number | symbol
:
type KeyOfAny = keyof any; // type KeyOfAny = string | number | symbol
也就是說,在 TypeScript 中,能接受作為 key 的型別只能是 string、number 或 symbol,其他的型別像是 boolean 或 function 是不能被當作 key 的。
當我們試著把 object key 指定為 boolean 時,TS 會報錯:
參考資料
- Keyof Type Operator @ TypeScript > Type Manipulation
- Object Types @ TypeScript > Everyday Types