いまさら JavaScript なんて書けるか!ということで、 Contentful JavaScript SDK を TypeScript で使います。 まずはライブラリのインストール:
$ pnpm add contentful
いれたあと、以下のようにライブラリを定義すると良い。
import contentful from "contentful"; const contentfulClient = contentful.createClient({ space: import.meta.env.CONTENTFUL_SPACE_ID, accessToken: import.meta.env.DEV ? import.meta.env.CONTENTFUL_PREVIEW_TOKEN : import.meta.env.CONTENTFUL_DELIVERY_TOKEN, host: import.meta.env.DEV ? "preview.contentful.com" : "cdn.contentful.com", }); export { contentfulClient };
基本、あとは contentfulClient
に生えているメソッドを使えば良いが、各エントリーについて型定義が欲しい。
そういった場合、一定の規則に従った型定義を作成する必要がある。
具体的には、以下の型定義と互換性がある必要がある。
type FieldsType = Record<string, any>; type EntrySkeletonType<Fields extends FieldsType = FieldsType, Id = string> = { fields: Fields; contentTypeId: Id; };
これだけみてもさっぱりなので、ここは非公式ライブラリで自動生成するのが良い。
ということで、以下のコマンドを実行する。
$ pnpm dlx cf-content-types-generator -s SPACE_ID -t CFPAT-XXXX --v10
SPACE_ID
には、型定義を生成したい Contentful のスペース ID を、 CFPAT-XXXX
には、 Content Management Token を設定する。
ここでしか使わないと思うので、該当トークンは使ったら破棄して良い。
また、 --v10
フラグは、 Contentful SDK のバージョンが v10 以降の場合に指定する必要がある。
いま普通にインストールすると、v10.1.6
あたりがインストールされるはずなので、この場合は指定する必要がある。
コマンドを実行すると、以下のような型定義が生成されるはず。
import type { ChainModifiers, Entry, EntryFieldTypes, EntrySkeletonType, LocaleCode, } from "contentful"; export interface TypeArticleFields { title: EntryFieldTypes.Symbol; slug: EntryFieldTypes.Symbol; body: EntryFieldTypes.RichText; published_at: EntryFieldTypes.Date; } export type TypeArticleSkeleton = EntrySkeletonType< TypeArticleFields, "article" >; export type TypeArticle< Modifiers extends ChainModifiers, Locales extends LocaleCode > = Entry<TypeArticleSkeleton, Modifiers, Locales>;
これのうち、 TypeArticleSkeleton
を getEntries
の型引数として渡すと良い。
// こんな感じ const entries = await contentfulClient.getEntries<ArticleSkeleton>({ content_type: "article", });
ということで、メモでした。