TypeScript
หน้านี้สอนอะไร
type ของเอกสารสร้างจาก config โดยไม่ต้อง build อย่างไร จะตั้งชื่อ type ใช้ในโค้ดอย่างไร และจะสร้างไฟล์ type ให้แอปที่ import config ไม่ได้อย่างไร
ควรอ่านก่อน: Local API
สร้างจาก config
ประกาศ config ด้วย defineConfig ซึ่งเก็บ literal type ไว้ (slug, ชื่อ field, ตัวเลือกของ select) Local API จึงมี type โดยไม่ต้องรันขั้นตอน generate:
const cms = await getEasyCMS(config) // ใน Nuxt ใช้ useEasyCMS()
const { docs } = await cms.find('posts')
docs[0].title // string (required: true)
docs[0].excerpt // string | null | undefined (ไม่บังคับ)
docs[0].tags // ('vue' | 'nuxt')[] (select แบบ hasMany)
docs[0].author // number | User (relationship: id หรือเอกสารเมื่อ populate)
docs[0].status // 'draft' | 'published' (drafts: true)
await cms.find('pots') // error: ไม่มี collection นี้
await cms.create('posts', { titel: 'Hi' }) // error: ไม่มี field นี้ และขาด `title`แต่ละ field กลายเป็น type อะไร:
| Field | Type |
|---|---|
text, textarea, email, slug, date | string (date เป็น ISO 8601) |
number | number |
boolean | boolean |
select | union ของตัวเลือก หรือ array ของตัวเลือกเมื่อใช้ hasMany |
relationship, upload | id หรือเอกสารที่เกี่ยวข้องเมื่อ populate เป็น array เมื่อใช้ hasMany |
group | object ของ field ข้างใน |
array | array ของแถวที่มี id และ field ของแถว |
blocks | array ของแถว มี type หนึ่งแบบต่อหนึ่ง block แยกกันด้วย blockType |
richText | เอกสารของ Tiptap |
json | unknown |
field ที่ไม่มี required: true เป็นแบบไม่บังคับ คือเป็น null หรือไม่มีค่า ส่วน field ที่ hidden จะไม่อยู่ใน type
Blocks
แถวของ field แบบ blocks เป็น union ให้ตรวจ blockType เพื่อแยกประเภท:
for (const section of post.sections ?? []) {
if (section.blockType === 'quote') section.author // เฉพาะแถว quote ที่มี author
}ตั้งชื่อ type
import type { CollectionDocument, CreateInput, GlobalDocument, UpdateInput } from '@easy-cms/core'
import type config from './easy-cms.config'
export type Post = CollectionDocument<typeof config, 'posts'>
export type NewPost = CreateInput<typeof config, 'posts'>
export type PostChanges = UpdateInput<typeof config, 'posts'>
export type Site = GlobalDocument<typeof config, 'site'>import type ทำให้ config (และ driver ของฐานข้อมูล) ไม่ถูกรวมเข้า bundle ฝั่ง browser component ก็ใช้ Post ได้
ใน Nuxt
server route คืนข้อมูลที่มี type และ useFetch ส่ง type ต่อไปให้หน้าเว็บ:
// server/api/posts.get.ts
export default defineEventHandler(async () => (await useEasyCMS()).find('posts'))<script setup lang="ts">
const { data } = await useFetch('/api/posts') // data.value.docs เป็น Post[]
</script>สร้างไฟล์ type สำหรับแอปอื่น
สำหรับ frontend ที่ import config ไม่ได้ เช่น แอป Vite ใน repo อื่นที่เรียก REST API:
npx easy-cms generate:types # เขียน easy-cms-types.ts
npx easy-cms generate:types --out ../web/src/cms.tspnpm exec easy-cms generate:types # เขียน easy-cms-types.ts
pnpm exec easy-cms generate:types --out ../web/src/cms.tsyarn easy-cms generate:types # เขียน easy-cms-types.ts
yarn easy-cms generate:types --out ../web/src/cms.tsbunx easy-cms generate:types # เขียน easy-cms-types.ts
bunx easy-cms generate:types --out ../web/src/cms.tsไฟล์นี้ไม่มี import: มี interface หนึ่งตัวต่อ collection และ global พร้อม map Collections และ Globals
import type { Post } from './easy-cms-types'
const res = await fetch('/api/cms/posts?limit=10')
const { docs }: { docs: Post[] } = await res.json()รันใหม่หลังเปลี่ยน config หรือใน CI เพื่อตรวจว่าไฟล์ยังตรงกับ config:
npx easy-cms generate:types && git diff --exit-code easy-cms-types.tspnpm exec easy-cms generate:types && git diff --exit-code easy-cms-types.tsyarn easy-cms generate:types && git diff --exit-code easy-cms-types.tsbunx easy-cms generate:types && git diff --exit-code easy-cms-types.ts