iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

Hello TypeScript 菜鳥系列 第 27

Day 26. TypeScript Type Manipulation:Indexed Accessed Types

  • 分享至 

  • xImage
  •  

昨天的文章提到 keyof 型別運算子可以用來取得物件鍵值(key)型別,並能將鍵值型別們union成一個型別;若單純從取得的型別來看,現在要認識的indexed accessed types 的作用和 keyof 正好相反。

Indexed accessed types是「透過 "索引" 鍵值來取得鍵值的型別_」,甚至能"索引"多個鍵值的型別並union成一個型別。

這裡的索引是動詞,可想成是「查找」,但光看繞口的說明可能會有點霧煞煞,直接來看一些例子。

這個例子是要取得物件型別的鍵值型別

interface Dog {
	name: string;
	age: number;
	hasOwner: boolean;
}

type D1 = Dog["name"];				// type D1 = string

type D2 = Dog["age" | "hasOwner"];		// type D2 = number | boolean


// Get types of all keys
type D3 = Dog["name" | "age" | "hasOwner"];	// type D3 = string | number | boolean

// or
type DogKeys = "name" | "age" | "hasOwner";
type D3Keystypes = Dog[Dogkeys];		// type D3Keystypes = string | number | boolean

// or
type D3KeyofTypes =  Dog[keyof Dog];		// type D3KeyofTypes = string | number | boolean

那如果Dog鍵值的型別有重複會怎麼樣?

interface Dog {
	name: string;
	age: number;
	hasOwner: boolean;
	h: number;
	w: number;
}

type D = Dog[keyof Dog];	// type D = string | number | boolean

結果不是 string | number | boolean | number | number,因為union不必重複型別。

union不必重複型別的原因在於,union型別的意思是:

(變數) 可以是A型別或是B型別

如上面例子的型別D代表 可以是 string 或 number 或 boolean型別

若能union重複型別,那 string | number | boolean | number | number 型別的意思會變成:

(變數) 可以是 string 或 number 或 boolean 或 number 或 number 型別

前面已經允許 可以是number型別 ,後面就不用再允許兩次可以是number型別了吧XD。

此外,若想取得陣列元素的型別,能用 typeof 型別運算子和 number 關鍵字去索引陣列元素來取得型別:

const dogs = [
    {
        name: "Harry",
        age: 2,
        hasOwner: true
    },
        {
        name: "Black",
        age: 5,
        hasOwner: false
    },

];

type DogName = typeof dogs[number]["name"];	// type DogName = string;

type Dog = typeof dogs[number];
/*
   type Dog = {	
	name: string;
	age: number;
	hasOwner: boolean;
   }
*/

在用索引方式取得型別時,有一點要注意:用來當作索引的是型別,不可是變數值(value)
前面例子的 "name""name" | "age" | "hasOwner" 其實都是literal型別,並非是變數值或屬性值。

如果用變數值取得型別,compiler會顯示多個錯誤:

let age = "age";
const hasOwner = "hasOwner";

type DogAge = Dog[age];			// error
type DogHasOwner = Dog[hasOwner];	// error

其中可以看到最重要的錯誤是:

'age' refers to a value, but is being used as a type here. Did you mean 'typeof age'?(2749)

除非變數是literal型別,並同時使用 typeof 型別運算子去取得變數literal型別,否則變數值是沒辦法索引型別的,就像下面例子中的 let age

// 1.
let age = "age";
const hasOwner = "hasOwner";

type DogAge = Dog[typeof age];			// error
type DogHasOwner = Dog[typeof hasOwner]		// ok, hasOwner is "hasOwner" type


// 2.
let ageType: "age" = "age";
const hasOwnerType: "hasOwner" = "hasOwner";

type DogAgeType = Dog[typeof ageType];			//  ok
type DogHasOwnerType = Dog[typeof hasOwnerType];	//  ok

這邊有個線上範例可以來玩玩看單純用 typeof agetypeof ageType 去取得indexed accessed types的差別。


參考資料
Indexed Access Types @TypeScript Handbook


上一篇
Day 25. TypeScript Type Manipulation: & Operator、typeof Operator、keyof Operator
下一篇
Day 27. TypeScript Type Manipulation:Conditional Types
系列文
Hello TypeScript 菜鳥31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言