Utility functions to ease Sanity schema development:
schema(typeName, schemaDefinition)
: used to define schemas that is consumed bycreateSchema
.field(typeName, fieldDefinition)
: used to define fields fordocument
,object
,file
andimage
schemas.arrayOf(typeName, arrayMemberDefinition)
: used to define of-entries inarray
schemas.typed<T>(anything)
: passthrough function to provide inline types in json objects.
- Typesafe Sanity schemas (and with that, autocompletion)
- Feature discovery of built-in Sanity features (types, options, validations)
- Breadcrumb-trails to relevant Sanity docs
- Feature discovery & documentation of extension types & features (custom input-resolver options, reusable schema-types etc.)
- Decrease time from idea to finished schema for developers, by embracing the above.
- Opt-in. Ie, this can be sprinkled into an existing codebase to gradually add type safety to schemas.
- Minimal runtime footprint. Should not mess with the schema provided by the developer.
npm i @snorreeb/sanity-typesafe-schemas
import { field, schema } from "@snorreeb/sanity-typesafe-schemas";
export const typesafeDocumentSchema = schema("document", {
name: "some-doc",
title: "Some document",
fields: [
field("string", {
name: "someField",
title: "Some title",
initialValue: "a",
options: {
list: [
{ value: "a", title: "A" },
{ value: "b", title: "B" },
],
layout: "radio",
},
}),
],
});
//@ts-expect-error schema is not correctly defined
const withErrorSchema = schema("string", {});
See code examples.
Use TypeScript declaration merging
to extend the types under @snorreeb/sanity-typesafe-schemas
:
// document-extension.ts
import "@snorreeb/sanity-typesafe-schemas";
declare module "@snorreeb/sanity-typesafe-schemas" {
interface DocumentSchema {
options?: {
custom?: boolean;
};
}
}
// somewhere using typesafe helpers
export const typesafeDocumentSchema = schema("document", {
/* omitted */
options: {
custom: true // custom is now a valid option for all document shemas
}
});
Define your schema type, and use TypeScript declaration merging
to extend SchemaDirectory
in @snorreeb/sanity-typesafe-schemas
:
// special-string-schema.ts
import { StringSchema } from "@snorreeb/sanity-typesafe-schemas";
export type SpecialStringSchema = Omit<StringSchema, "type"> & {
type: "special-string";
options: {
special: string;
};
};
// schema-directory-extension.ts
import "@snorreeb/sanity-typesafe-schemas";
declare module "sanity-typesafe-schemas-alpha" {
interface SchemaDirectory {
"special-string": SpecialStringSchema;
}
}
// somewhere using typesafe helpers
export const specialStringSchema = schema(
"special-string", // special-string is now a valid, autocompletable type
{/* omitted */}
);
The 'custom'
string is a general escape hatch that still provides some safety.
Use alongside the typed
generic helper function, to define inline types.
import { schema, typed } from "@snorreeb/sanity-typesafe-schemas";
export const stringSchemaUsedByNameSomewhereElse = schema("custom", {
type: "string", // when using 'custom', type must be provided here
name: "this-name-is-used-in-another-schema",
title: "Custom stringtype for whatever reason",
inputComponent: () => "Render me softly",
options: typed<{customOption: boolean}>({
customOption: true
})
});
Title is optional in Sanity Studio, but will result in console.log warnings if omitted. Therefore, it is required by the schema-helpers.
To set an undefined title anyway, hack-cast it:
const mySchema = schema('object', {
title: undefined as unknown as string
});
Compiled to javascript, the helper functions look like this:
function schema(type, schema) {
return {
type,
...schema
}
}
function field(type, schema) {
return {
type,
...schema
}
}
function arrayOf(type, schema) {
return {
type,
...schema
}
}
function typed(anything) {
return anything
}
Ie, they are basically an identity functions with no overhead.
Types in @sanity/types
are the compiled definition of schemas, obtained
after passing schema-definitions to createSchema
.
The schema-definition types are subtly different and may or may not contain internal fields. Terefore, types are reimplemented to resemble the Sanity schema documentation to avoid confusion and/or add jsdocs.
(╯°□°)╯︵ ┻━┻
We will get there eventually! 🤞
Until then: use the escape hatches & typed
helper where necessary.
┬─┬ノ(º_ºノ)