TypeScript
This article shows how to use TypeScript in your Next.js project. Types for your Prismic content are automatically integrated into your project using the latest Prismic tools.
TypeScript is an extra layer above JavaScript that helps you write resilient code. It is a language that understands the data moving throughout your app. By using TypeScript, you can more quickly and more confidently add, edit, and delete code.
If you do something wrong, your code editor and the TypeScript compiler prompt an error before deploying to production.
Using TypeScript does not add significant overhead to projects in most cases. Adopting TypeScript generally results in less time spent diagnosing bugs and refactoring legacy code later in a project’s life.
This guide assumes your project is already set up with TypeScript.
If your Next.js project does not currently use TypeScript, follow Next.js’s official TypeScript guide for existing projects before continuing.
JSDoc gives you most of TypeScript’s benefits while writing in JavaScript. When using JSDoc, types are declared using code comments.
Examples throughout this article are provided in TypeScript and JSDoc formats.
Slice Machine generates a prismicio-types.d.ts
file in your project containing types for your Prismic content. The file will be regenerated any time content models are added or modified.
All types are accessible by importing the Content
namespace from @prismicio/client
.
import type { Content } from '@prismicio/client'
Automatic type generation was added in Slice Machine v0.5.1
Update to the latest version for the best experience.
Projects that do not use Slice Machine can use the prismic-ts-codegen
CLI to generate types. See the prismic-ts-codegen Technical Reference to learn more about the tool and its configuration options.
We recommend creating a prismicio.ts
file at the root of your project containing a createClient()
function. This function is used wherever a Prismic client is needed, including getStaticProps()
and API endpoints. See the Set up Prismic article for more details.
To type your createClient()
function, use @prismicio/next
's CreateClientConfig
type.
- TypeScript
- JavaScript
import * as prismic from '@prismicio/client'
import * as prismicNext from '@prismicio/next'
export function createClient({
previewData,
req,
...config
}: prismicNext.CreateClientConfig = {}) {
const client = prismic.createClient('your-repo-name', config)
prismicNext.enableAutoPreviews({ client, previewData, req })
return client
}
import * as prismic from '@prismicio/client'
import * as prismicNext from '@prismicio/next'
/** @param {import("@prismicio/next").CreateClientConfig} */
export function createClient({ previewData, req, ...config } = {}) {
const client = prismic.createClient('your-repo-name', config)
prismicNext.enableAutoPreviews({ client, previewData, req })
return client
}
Types generated by prismic-ts-codegen
are automatically integrated into @prismicio/client
.
Automatic client integration was introduced in @prismicio/client
v6.6.0
Update to the latest version for the best experience.
Queries that reference a page type, such as getByUID()
or getAllByType()
, are automatically TypeScript-typed.
In the following example, a Page document is queried and automatically typed with PageDocument
:
import type { GetStaticPropsContext } from 'next'
import { createClient } from '../prismicio'
// ...
export async function getStaticProps({
previewData,
}: GetStaticPropsContext) {
const client = createClient({ previewData })
// ^ Automatically contains references to document types
const page = await client.getByUID('page', 'home')
// ^ Typed as PageDocument
return {
props: {
page,
},
}
}
Client methods that do not reference a specific document type, such as getAllByTag()
or getFirst()
, are TypeScript-typed using a union of all generated document types, allowing you to narrow the type in your own code.
const drinks = await client.getAllByTag('drinks')
// ^ Typed as PageDocument[] | MenuItemDocument[] | SettingsDocument[]
All query methods accept a type parameter to override or specify a return type. This parameter is useful when a specific type is not automatically inferred.
- TypeScript
- JavaScript
import type { Content } from '@prismicio/client'
const drinks = await client.getAllByTag<Content.MenuItemDocument>('drinks')
/** @type {import('@prismicio/client').Content.MenuItemDocument[]} */
const drinks = await client.getAllByTag('drinks')
See the @prismicio/client Technical Reference to learn more about the package and its TypeScript support.
Page components can be typed using the inferred type from the page’s getStaticProps()
or getServerSideProps()
function.
Next.js provides InferGetStaticPropsType
and InferGetServerSidePropsType
helpers for this purpose.
In the following example, page props are typed in PageProps
:
- TypeScript
- JavaScript
import type { InferGetStaticPropsType, GetStaticPropsContext } from 'next'
import { createClient } from '../prismicio'
type PageProps = InferGetStaticPropsType<typeof getStaticProps>
export default function Page({ page }: PageProps) {
// `page` is typed as PageDocument.
}
export async function getStaticProps({
previewData,
}: GetStaticPropsContext) {
const client = createClient({ previewData })
const page = await client.getByUID('page', 'home')
// ^ Typed as PageDocument
return {
props: {
page,
},
}
}
import { createClient } from '../prismicio'
/** @typedef {import('next').InferGetStaticPropsType<typeof getStaticProps>} PageProps */
/** @param {PageProps} */
export default function Page({ page }) {
// `page` is typed as PageDocument.
}
/** @param {import('next').GetStaticPropsContext} */
export async function getStaticProps({ previewData }) {
const client = createClient({ previewData })
const page = await client.getByUID('page', 'home')
// ^ Typed as PageDocument
return {
props: {
page,
},
}
}
Pages with route parameters, such as src/pages/[uid].tsx
, can type their parameters by passing an object type to GetStaticPropsContext
or GetServerSidePropsContext
, depending on which data fetching API is used.
In the following example, route parameters are typed in PageParams
:
- TypeScript
- JavaScript
import type { GetStaticPropsContext } from 'next'
type PageParams = { uid: string }
// ...
export async function getStaticProps({
params,
previewData,
}: GetStaticPropsContext<PageParams>) {
// `params` is typed as PageParams
}
/**
* @typedef {Object} PageParams
* @property {string} uid
*/
// ...
/** @param {import('next').GetStaticPropsContext<PageParams>} */
export async function getStaticProps({
params,
previewData,
}) {
// `params` is typed as PageParams
}
Slice components can be typed using @prismicio/react
's SliceComponentProps
type which accepts a slice’s generated type as a type parameter.
Using SliceComponentProps
ensures the component is compatible with @prismicio/react
's <SliceZone>
component.
In the following example, a Text slice’s component is fully typed:
- TypeScript
- JavaScript
import type { Content } from '@prismicio/client'
import type { SliceComponentProps } from '@prismicio/react'
export type TextProps = SliceComponentProps<Content.TextSlice>
export default function Text({ slice }: TextProps) {
// `slice` is typed as TextSlice.
}
/**
* @typedef {import("@prismicio/client").Content.TextSlice} TextSlice
* @typedef {import("@prismicio/react").SliceComponentProps<TextSlice>} TextProps
*
* @param {TextProps}
*/
export default function Text({ slice }) {
// `slice` is typed as TextSlice.
}
Content relationship and link fields allow querying for a linked document’s content using the graphQuery
or fetchLinks
query options. These queries are not automatically typed, but they can be defined in your app’s code.
In the following example, a Page document is queried with a fetchLinks
query option. The relatedBlogPost
's field value will include the selected Blog Post’s title
and description
fields within the data
property.
- TypeScript
- JavaScript
import type { GetStaticPropsContext } from 'next'
import type { Content } from '@prismicio/client'
import { createClient } from '../prismicio'
export async function getStaticProps({
previewData,
}: GetStaticPropsContext) {
const client = createClient({ previewData })
// The `relatedBlogPost` field contains the blog post's `title` and
// `description` fields.
const page = await client.getByUID<
Content.PageDocument & {
data: {
relatedBlogPost: {
data: Pick<Content.BlogPostDocument['data'], 'title' | 'description'>
}
}
}
>('page', 'home', {
fetchLinks: [
'my.relatedBlogPost.title',
'my.relatedBlogPost.description',
],
})
return {
props: {
page,
},
}
}
import { createClient } from '../prismicio'
/** @param {import('next').GetStaticPropsContext} */
export async function getStaticProps({ previewData }) {
const client = createClient({ previewData })
/**
* @typedef {import("@prismicio/client").Content} Content
*
* @typedef {object} Relation
* @property {{ relatedBlogPost: { data: RelationData } }} data
*
* @typedef {Content.ArticleDocument["data"]} ArticleDocumentData
* @typedef {Pick<ArticleDocumentData, "title" | "description">} RelationData
*
* @type {Content.PageDocument & Relation}
*/
const page = await client.getByUID('page', 'home', {
fetchLinks: [
'my.relatedBlogPost.title',
'my.relatedBlogPost.description',
],
})
return {
props: {
page,
},
}
}
Can't find what you're looking for?
Need technical Support? Spot an error in the documentation? Get in touch with us on our Community Forum.