Thinkmill / Thinkmill/keystatic
Expose a type that accepts a Record<string, ComponentSchema> and returns a resolved entry type
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.4k
- Forks
- 159
- Avg merge
- 21h 41m
- Merged PRs (30d)
- 2
Description
related discussion: https://github.com/Thinkmill/keystatic/discussions/211#discussioncomment-8105588
Currently I'm trying to compose types of my schema fragments that go into the keystatic config.
I don't want types for an item in a collection.
What I'm after here would be analogous to types created by tsgql for GQL fragments.
I've come up with the follow that provides me with resolved types from fragments:
import type { ComponentSchema, ValueForReadingDeep, ValueForReading, SlugFormField } from '@keystatic/core';
type ValueForReadingWithMode<
Schema extends ComponentSchema,
ResolveLinkedFiles extends boolean | undefined
> = ResolveLinkedFiles extends true
? ValueForReadingDeep<Schema>
: ValueForReading<Schema>;
type ResolvedSchemaFragment<Schema extends Record<string, ComponentSchema>, SlugField = void> = {
[Key in keyof Schema]: SlugField extends Key
? Schema[Key] extends SlugFormField<any, any, any, infer SlugSerializedValue>
? SlugSerializedValue
: ValueForReadingWithMode<Schema[Key], true>
: ValueForReadingWithMode<Schema[Key], true>;
}
The ResolvedSchemaFragment is already present in keystatic, but it's hidden behind the reader factory return type.
The above allows me to create schema fragments that I can compose into collections within the keystatic config and export them as usable types in the context of how they're finally consumed.
import { config, fields, collection } from '@keystatic/core';
import type { ComponentSchema, ValueForReadingDeep, ValueForReading, SlugFormField } from '@keystatic/core';
type ValueForReadingWithMode<
Schema extends ComponentSchema,
ResolveLinkedFiles extends boolean | undefined
> = ResolveLinkedFiles extends true
? ValueForReadingDeep<Schema>
: ValueForReading<Schema>;
type ResolvedSchemaFragment<Schema extends Record<string, ComponentSchema>, SlugField = void> = {
[Key in keyof Schema]: SlugField extends Key
? Schema[Key] extends SlugFormField<any, any, any, infer SlugSerializedValue>
? SlugSerializedValue
: ValueForReadingWithMode<Schema[Key], true>
: ValueForReadingWithMode<Schema[Key], true>;
}
const PublishablePageSchema = {
title: fields.slug({ name: { label: 'Title' }}),
date: fields.date({ label: 'date' }),
stage: fields.text({ label: 'Status' }),
}
export type PublishablePageFragment = ResolvedSchemaFragment<
typeof PublishablePageSchema, 'title'
>
const TemplatablePageSchema = {
theme: fields.text({ label: 'Theme' }),
template: fields.select({
label: 'Template',
options: [{
label: 'Post',
value: 'post'
},{
label: 'Page',
value: 'page'
}],
defaultValue: 'post',
}),
}
export type TemplatablePageFragment = ResolvedSchemaFragment<
typeof TemplatablePageSchema
>
const ContentfulPageSchema = {
content: fields.document({
label: 'Content',
formatting: true,
dividers: true,
links: true,
images: true,
}),
}
export type ContentfulPageFragment = ResolvedSchemaFragment<
typeof ContentfulPageSchema
>
export default config({
storage: {
kind: 'local',
},
collections: {
pages: collection({
label: 'About',
slugField: 'title',
path: 'src/content/about/*',
format: { contentField: 'content' },
entryLayout: 'content',
schema: {
...PublishablePageSchema,
...TemplatablePageSchema,
...ContentfulPageSchema,
}
}),
}
});
This results in allow me to compose types for my components like thus:
I guess where I'm going with this is that it would be useful to others if the types behind the createReader were available as public types for the above purpose.
Here's the part I extracted and adapted https://github.com/Thinkmill/keystatic/tree/main/packages/keystatic/src/app#L98C1-L124C5
wh
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the createReader-related types in packages/keystatic/src/app, particularly the linked lines around 98-124, and compare them with the requested ResolvedSchemaFragment type. Trace how the existing type is exposed through the reader factory, then make the resolved entry type publicly importable and verify that composed schema fragments can use it as shown.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100