Skip to content

Instantly share code, notes, and snippets.

@essejmclean
Created June 13, 2024 15:19
Show Gist options
  • Save essejmclean/25c340cef75a9e69a87070b83e161a89 to your computer and use it in GitHub Desktop.
Save essejmclean/25c340cef75a9e69a87070b83e161a89 to your computer and use it in GitHub Desktop.
Type-safe wrapper around Prismic's `isFilled.contentRelationship` function to make link fields more type-safe.
/**
* Type-safe wrapper around Prismic's `isFilled.contentRelationship` function to make link fields more type-safe.
* You'll want to make sure that your Prismic client is set up to handle typed content.
*
* If using Next.js and Slice Machine, you can use the `@prismicio/client` package to set up typed content.
* @see {@link https://prismic.io/docs/typescript-nextjs} for more information.
*
* Prismic also offers support via the `prismic-ts-codegen` package.
* @see {@link https://prismic.io/docs/technical-reference/prismic-ts-codegen} for more information.
*/
import {
type Content,
type FilledContentRelationshipField,
isFilled,
type LinkField,
} from "@prismicio/client";
// Extracts the data of a specific document type from Prismic content
type DocumentData<TDocumentType extends Content.AllDocumentTypes["type"]> =
Extract<Content.AllDocumentTypes, { type: TDocumentType }>["data"];
/**
* Checks if a link field in Prismic is a filled content relationship field and contains the specified field IDs.
* This is useful for checking if a link field is a valid link to a specific document type and contains the specified field IDs.
* This acts as a wrapper around the `isFilled.contentRelationship` function from Prismic to make link fields more type-safe.
*
* @template TDocumentType - The type of the document.
* @template TFieldID - The field IDs to check within the document data.
* @param {LinkField} linkField - The link field to check.
* @param {TDocumentType} documentType - The type of the document to match against.
* @param {TFieldID[]} fieldIDs - The field IDs to check within the document data.
* @returns {linkField is FilledContentRelationshipField & { data: { [P in keyof DocumentData<TDocumentType> as P extends TFieldID ? P : never]: DocumentData<TDocumentType>[P]; } }} - Returns true if the link field is a filled content relationship field and contains the specified field IDs.
*
* @example
* ```ts
* import { isFilledLinkedContent } from "./is-filled-linked-content";
*
* const isValidLink = isFilledLinkedContent(linkField, "article", ["title"]);
* ```
*/
export function isFilledLinkedContent<
TDocumentType extends Content.AllDocumentTypes["type"],
TFieldID extends keyof DocumentData<TDocumentType>,
>(
linkField: LinkField,
documentType: TDocumentType,
fieldIDs: TFieldID[]
): linkField is FilledContentRelationshipField & {
data: {
[P in keyof DocumentData<TDocumentType> as P extends TFieldID
? P
: never]: DocumentData<TDocumentType>[P];
};
} {
return (
// Check if the link field is a filled content relationship field
isFilled.contentRelationship(linkField) &&
// Check if the link field's type matches the specified document type
linkField.type === documentType &&
// Ensure the link field's data is an object and not null
typeof linkField.data === "object" &&
linkField.data !== null &&
// Check if all specified field IDs exist in the link field's data
fieldIDs.every(
(fieldID) => fieldID in (linkField.data as Record<string, unknown>)
)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment