Sanity TypeGen 可以透過分析 Sanity 定義的 schema 跟使用 GROQ String helper 定義的變數產生 TypeScript 型別檔。
到 Sanity 專案下使用指令
$ cd sanity-project
$ sanity schema extract
執行後會產生一個 schema.json
檔案在專案目錄下。
內容可以先不用看,只要知道他是從專案內 schema 內產生的檔案,作為後續 typegen 產生的用途。
內容大概是這樣 ( 可以忽略掉,沒有特別事情通常不會去看 )
{
"name": "blogPost",
"type": "document",
"attributes": {
"_id": {
"type": "objectAttribute",
"value": {
"type": "string"
}
},
"_type": {
"type": "objectAttribute",
"value": {
"type": "string",
"value": "blogPost"
}
},
"_createdAt": {
// ...
}
},
接下來用指令 sanity typegen generate
sanity typegen generate
執行後會產生一個 sanity.types.ts
的型別檔,這就是我們要的型別檔案了。
主要就是根據 schema 產生這段:
// ...
export type BlogPost = {
_id: string
_type: 'blogPost'
_createdAt: string
_updatedAt: string
_rev: string
title?: string
slug?: string
subtitle?: string
heroImage?: {
asset?: {
_ref: string
_type: 'reference'
_weak?: boolean
[internalGroqTypeReferenceTo]?: 'sanity.imageAsset'
}
hotspot?: SanityImageHotspot
crop?: SanityImageCrop
_type: 'image'
}
content?: string
publishedAt?: string
tags?: Array<string>
}
// ...
手動複製這個檔案到引入這個檔案後,就可以在任意 TypeScript 專案內使用了。
像移到 next-app
內的 ./app/sanity/sanity.types.ts
接著就可以引入了:
import { client } from "@/app/sanity/lib/client";
import { BLOG_POSTS_QUERY } from "@/app/sanity/lib/queries";
// 引入型別
import type { BlogPost } from "./sanity/sanity.types";
export default async function Home() {
// 宣告型別
const posts = await client.fetch<BlogPost[]>(BLOG_POSTS_QUERY);
return (
<ul className="home-page">
{/* 型別就沒錯誤了 */}
{posts.map((post) => (
<li key={post._id}>
<a href={`/posts/${post?.slug}`}>{post?.title}</a>
</li>
))}
</ul>
);
}
這就是最基本的使用了。
可以看到型別檔內每一個欄位都是選填的,但是在型別 schema 設定的時候是有設定必填的,像是 title 就是必填欄位。
defineField({
name: 'title',
title: '標題',
type: 'string',
validation: (rule) => rule.required(),
}),
這欄位是有 required()
定義的,可是輸出型別後卻是選填的:
// sanity.types.ts
export type BlogPost = {
_id: string;
_type: "blogPost";
_createdAt: string;
_updatedAt: string;
_rev: string;
title?: string; // 選填
slug?: string; // 選填
subtitle?: string;
}
只要在產生 schema 指令 sanity schema extract
加上 --enforce-required-fields
參數,最後再使用 sanity typegen generate
就可以了。
sanity schema extract --enforce-required-fields
sanity typegen generate
這樣產生出來的型別檔,就不再是選填的了。
export type BlogPost = {
_id: string
_type: 'blogPost'
_createdAt: string
_updatedAt: string
_rev: string
title: string
slug: string
subtitle?: string
// ...
}