types.ts 與 content.config.ts的差異

從製作照片牆來理解types.ts 與 content.config.ts的功能及角色差異

Written by

Published on: Sun Jul 05

astro

basic

在製作照片牆的時候,出現一個之前製作部落格文章的時候沒有用過的檔案: type.ts

從內容看起來兩個長得很類似,所以搞不太清楚他們在製作過程中的用途差異,就問了一下AI,以下就整理一下結論。


結論

可以想成 「入境檢查」跟「公司員工證」,這兩個比喻通常很好理解。


content.config.ts:入境檢查(檢查資料)

每一篇 Markdown 都像一個旅客。

---
title: Sunset
image: /sunset.jpg
tags: [travel, sea]
---

當 Astro 讀取它時,會先經過 content.config.ts。

它會問:「有沒有 title?」、「image 是字串嗎?」、「tags 是不是陣列?」 如果不符合,就不讓它進來(編譯錯誤)。 所以它的工作只有一句話:檢查資料是否合法。

以實際製作流程來說,沒有在content.config.ts輸入相關資料,絕對會報錯。(有點像是建立資料庫的規則)


types.ts:員工證(程式內使用)

資料通過檢查後,開始在你的程式裡流動。 例如:

Gallery.astro
GalleryClient
GalleryCard

這些元件彼此約定: 「我收到的圖片物件長這樣。」

interface GalleryItem {
id: string
title: string
image: string
tags: string[]
}

這就是 types.ts 的工作。 它不是檢查 Markdown,而是讓元件知道: 「我要接收這種資料。」


一張圖看懂

Markdown
content.config.ts「檢查格式」
資料合法
types.ts「告訴程式:接下來都用這種型別」
GalleryClient
GalleryCard

Q:為什麼還需要 types.ts?

很多小型 Astro 專案其實可以完全不寫 types.ts

但當你開始做:

export interface GalleryItem {
id: string;
title: string;
image: string;
tags: string[];
}

所有元件都引用同一份定義,就不用每個檔案都重寫一次,也比較容易維護。


如果這個照片牆有tag的filter,那會跟哪個比較相關?

答案是:兩個都會用到,但用途不同。 假設你的照片都有標籤:

---
title: Sunset
tags:
- travel
- sea
---

content.config.ts:確保每張照片都有正確的 tags

例如:

schema: z.object({
title: z.string(),
tags: z.array(z.string()),
})

它負責檢查:


types.ts:讓 Filter 知道可以使用 tags

例如:

export interface GalleryItem {
id: string;
title: string;
tags: string[];
}

因為 GalleryClient、TagFilter、GalleryCard 都會用到 tags。 例如:

const filteredImages = images.filter(image =>
image.tags.includes(selectedTag)
);

如果 GalleryItem 沒有定義 tags,TypeScript 就會提示錯誤。 所以它負責的是程式怎麼使用 tags


用你的資料流來看

Markdown
content.config.ts
「tags 一定要存在,而且是 string[]」
getCollection()
map → GalleryItem
types.ts
「GalleryItem 有 tags:string[]」
GalleryClient
├── TagFilter
├── useState(selectedTag)
└── filter(images)
GalleryGrid

可以看到:

所以 Tag Filter 的功能本身,比較偏向 types.ts,因為它是在程式裡操作 GalleryItem 的 tags 欄位;而 content.config.ts 則是確保這個欄位一開始就存在且格式正確。