DEV Community

Cover image for TS - Partial 用法及解析
FakeStandard
FakeStandard

Posted on

TS - Partial 用法及解析

Typescript 的 Utility Types 有很多,Partial 就是其中之一

Partial 的描述官方是這麼說的

Constructs a type with all properties of Type set to optional.
This utility will return a type that represents all subsets of a give type.

對岸碼農基本上直接翻譯再加上互相抄來抄去,描述都只有一種

Partial 可以快速把某个接口类型中定义的所有属性变成可选的。

其實不完全正確。因為 Partial 並非像上述所說直接把介面中的屬性變成可選,事實上它會複製一份 Type,並將屬性全部設置為可選的,也就是將所有屬性加上 ? ,所以它是產生了一個新的 Type,並非改變原始型別,舉個例子:

interface Student {
    id: number
    name: string
    address: string
}

const Andy: Student = {
    id: 1,
    name: 'Andy'
}
Enter fullscreen mode Exit fullscreen mode

先定義 Student 介面,接著宣告型別為 Student 的變數,因為未分配 address 的關係,我們得到以下錯誤

patial-001

該錯誤表示 address 在 Student 型別中是必要的屬性,在不改變 Student 定義下,有兩種解決方法,一種是分配 address 毫無懸念,另一種是定義新的介面,將 address 設為可選的,像是這樣

interface NewStudent {
    id: number
    name: string
    address?: string // 定義為可選的
}

// 沒有填寫 address 也不會報錯
const Andy: NewStudent = {
    id: 1,
    name: 'Andy'
}
Enter fullscreen mode Exit fullscreen mode

嗯...好像有點奇怪,相似的介面為什麼要寫兩個?假若再添加一個新屬性 age,其情況與 address 相同,不就要反覆定義新的介面?而這些介面差異只在於屬性的可選性...

此時就是端出 Partial 的好時機,我們不需要定義新的介面,而是讓 Partial 去複製一份新的物件型別,其所有屬性就會變成可選。

改良上面的例子

interface Student {
    id: number
    name: string
    address: string
}

const Andy: Partial<Student> = {
    id: 1,
    name: 'Andy'
}
Enter fullscreen mode Exit fullscreen mode

如此一來,不定義 address 也不會報錯,就算不定義其他屬性也不會報錯,因為此時 Andy 的型別 Partial<Student> 會長這樣

{
    id?: number
    name?: string
    address?: string
}
Enter fullscreen mode Exit fullscreen mode

發現了嗎?所有 property 都是 optional!所以說 Partial 到底是如何實現的?來看原始碼

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};
Enter fullscreen mode Exit fullscreen mode

只有一句重點 [P in keyof T]? :T[P] (關於 inkeyof 不再贅述)

解析
在 type 內部宣告一個變數 P,迭代型別 T 的每個 property,將每次遍歷結果分配給 P 以及設置 P 為 optional。

定義新的 type 為 Partial<Student>

interface Student {
    id: number
    name: string
    address: string
    age: number
}

type StudentInfo = Partial<Student>

Enter fullscreen mode Exit fullscreen mode

檢查 StudentInfo

partial-002

將 Student 型別分配給 Partial<T> ,它會返回一個新的型別 StudentInfo,其所有的 property 皆設置為可選的。

了解原理後,嘗試自行實作 Partial

type StudentPartial<T> = {
    [P in keyof T]?: T[P]
}

const Andy: StudentPartial<Student> = {
    id: 1,
    name: 'Andy'
}
Enter fullscreen mode Exit fullscreen mode

一一拆解後其實並不難,宛如一塊小蛋糕,適時地使用 Partial,讓程式碼更乾淨簡潔吧!


Thanks for reading the article 🌷 🌻 🌼

If you like it, please don't hesitate to click heart button ❤️
or follow my GitHub ⭐ I'd appreciate it.


Top comments (0)