iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0

Sanity TypeGen

Sanity TypeGen 可以透過分析 Sanity 定義的 schema 跟使用 GROQ String helper 定義的變數產生 TypeScript 型別檔。

透過 schema 檔產生的型別檔

到 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
  // ...
}

上一篇
Day 7 - Next.js 與 Sanity 專案連線
下一篇
Day 9 - Sanity TypeGen 進階設定
系列文
用 Sanity 跟 Nextjs 重寫個人部落格30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言