Package Exports
- @sanity-typed/types
- @sanity-typed/types/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@sanity-typed/types) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@sanity-typed/types
Typed Sanity Documents with zero schema changes!
Install
npm install @sanity-typed/types sanity
Usage
Use defineConfig
, defineType
, defineField
, and defineArrayMember
from this library exactly as you would from sanity's own exports. Then, you can InferSchemaValues
to have the typescript types!
// import { defineArrayMember, defineConfig, defineField, defineType } from "sanity";
import {
defineArrayMember,
defineConfig,
defineField,
defineType,
} from "@sanity-typed/types";
import type { InferSchemaValues } from "@sanity-typed/types";
// Corresponding example: https://www.sanity.io/docs/schema-field-types#e5642a3e8506
// No changes using defineArrayMember, defineField, and defineArrayMember https://www.sanity.io/docs/schema-field-types
const product = defineType({
name: "product",
type: "document",
title: "Product",
fields: [
defineField({
name: "productName",
type: "string",
title: "Product name",
}),
defineField({
name: "tags",
type: "array",
title: "Tags for item",
of: [
defineArrayMember({
type: "object",
name: "tag",
fields: [
{ type: "string", name: "label" },
{ type: "string", name: "value" },
],
}),
],
}),
],
});
// No changes using defineConfig https://www.sanity.io/docs/config-api-reference
const config = defineConfig({
// ...
schema: {
types: [
product,
// ...
],
},
});
export default config;
// This is where the magic happens!
type Values = InferSchemaValues<typeof config>;
// Import Product type into your application!
export type Product = Values["product"];
/**
* Product === {
* _createdAt: string;
* _id: string;
* _rev: string;
* _type: "product";
* _updatedAt: string;
* productName?: string;
* tags?: ({
* label?: string;
* value: string;
* })[];
* };
**/
Named/Aliased Types
const foo = defineType({
name: "foo",
type: "document",
fields: [
defineField({
name: "bar",
type: "bar",
}),
],
});
const bar = defineType({
name: "bar",
type: "object",
fields: [
defineField({
name: "baz",
type: "boolean",
}),
],
});
const config = defineConfig({
// ...
schema: {
types: [
foo,
bar,
// ...
],
},
});
export default config;
type Values = InferSchemaValues<typeof config>;
export type Foo = Values["foo"];
/**
* Foo === {
* _createdAt: string;
* _id: string;
* _rev: string;
* _type: "foo";
* _updatedAt: string;
* bar?: {
* _type: "bar";
* } & {
* baz?: boolean;
* };
* };
**/
Plugin Types
// import { definePlugin } from "sanity";
import { definePlugin } from "@sanity-typed/types";
const foo = defineType({
name: "foo",
type: "document",
fields: [
defineField({
name: "bar",
type: "bar",
}),
],
});
// No changes using definePlugin https://www.sanity.io/docs/developing-plugins
const barPlugin = definePlugin({
name: "plugin",
schema: {
types: [
defineType({
name: "bar",
type: "object",
fields: [
defineField({
name: "baz",
type: "boolean",
}),
],
}),
],
},
});
const config = defineConfig({
// ...
schema: {
types: [
foo,
// ...
],
},
plugins: [barPlugin()],
});
export default config;
type Values = InferSchemaValues<typeof config>;
export type Foo = Values["foo"];
/**
* Foo === {
* _createdAt: string;
* _id: string;
* _rev: string;
* _type: "foo";
* _updatedAt: string;
* bar?: {
* _type: "bar";
* } & {
* baz?: boolean;
* };
* };
**/
Goals
Typescript was an after-the-fact concern with sanity, since the rise of typescript happened after sanity took off. The define*
methods are a good start, but they only help restrict the schema, not type the document types. There's been attempts, namely sanity-codegen
and @sanity-typed/schema-builder
, but they take the approach of creating a new way of building schemas. The drop-in replacement approach allows for zero migration cost.
The long term goal is to deprecate the monorepo altogether. Building this seperately was to move quickly and these features should be in sanity directly (and is likely one of their internal goals). The idea is to introduce these changes iteratively into sanity itself while removing them from this library, until it's reduced to simply passing through the define*
methods directly, and will then be deprecated.
This shouldn't deter you from using it! Under the hood, it's passing all the inputs to sanity's native define*
methods, so you shouldn't have any runtime differences. With all the typings being attempting to make their way into sanity, you should keep all the benefits of just importing the define*
methods and noticing no differences.
Migrations
Migrating from 2.x to 3.x
InferSchemaValues
InferSchemaValues<typeof config>
used to return a union of all types but now returns an object keyed off by type. This is because using Extract
to retrieve specific type was difficult. Object types would have a _type
for easy extraction, but all the other types were less reliable (i.e. arrays and primitives).
export default config;
type Values = InferSchemaValues<typeof config>;
- export type Product = Extract<Values, { _type: "product" }>
+ export type Product = Values["product"];
InferValue
Types used to be inferred using InferValue<typeof type>
for easy exporting. Now, InferSchemaValues<typeof config>
needs to be used, and individual types keyed off of it. The reason for this is that only the config has context about aliased types, so InferValue
was always going to be missing those values.
const product = defineType({
name: "product",
type: "document",
title: "Product",
fields: [
// ...
],
});
- export type Product = InferValue<typeof product>;
const config = defineConfig({
// ...
schema: {
types: [
product,
// ...
],
},
});
export default config;
type Values = InferSchemaValues<typeof config>;
+ export type Product = Values["product"];
You can still use _InferValue
but this is discouraged, because it will be missing the context from the config:
const product = defineType({
name: "product",
type: "document",
title: "Product",
fields: [
// ...
],
});
- export type Product = InferValue<typeof product>;
+ export type Product = _InferValue<typeof product>;