Get TypeScript Type from JSON Schema
Simply generate TypeScript types from JSON Schema.
It has less functionality than json-schema-to-ts
, but supports circular references of $ref
.
npm install -D git+https://github.com/misskey-dev/schema-type
# or
yarn add -D git+https://github.com/misskey-dev/schema-type
# or
pnpm add -D git+https://github.com/misskey-dev/schema-type
import type { SchemaType, JSONSchema7 } from 'schema-type';
const schema = {
type: 'string',
} as const satisfies JSONSchema7;
type MyString = SchemaType<typeof schema>; // will `string`
import type { JSONSchema7, JSONSchema7Definition, GetDef, GetRefs, GetRefsKeys } from 'schema-type';
// Define as Record but key is ignored (you must specify key by `$id`).
const refs = {
Id: {
$id: 'https://example.com/schemas/Id',
type: 'string',
},
Note: {
$defs: {
poll: {
type: 'array',
items: {
type: 'object',
properties: {
text: { type: 'string' },
count: { type: 'number' },
},
},
required: ['text', 'count'],
}
},
$id: 'https://example.com/schemas/Note',
type: 'object',
properties: {
text: { type: 'string' },
poll: { $ref: '#/$defs/poll' },
fileIds: {
type: 'array',
items: { $ref: 'https://example.com/schemas/Id' },
},
replies: {
type: 'array',
items: { $ref: 'https://example.com/schemas/Note' },
}
},
required: ['text', 'replies'],
},
} as const satisfies Record<string, JSONSchema7Definition>;
type Refs = typeof refs;
// GetDef<References (global references) extends JSONSchema7Definition[], Key[, IsResponse, Prefix]>
export type Def<x extends GetRefsKeys<Refs>> = GetDef<GetRefs<Refs>, x>;
// With prefix
export type Packed<x extends GetRefsKeys<Refs, 'https://example.com/schemas/'>> = GetDef<GetRefs<Refs>, x, false, 'https://example.com/schemas/'>;
type Id = Def<'https://example.com/schemas/Id'> | Packed<'Id'>;
type Poll = Def<'https://example.com/schemas/Note#/$defs/poll'> | Packed<'Note#/$defs/poll'>;
import type { ..., SchemaType } from 'schema-type';
const refs = {
// ...
} as const satisfies Record<string, JSONSchema7Definition>;
type Refs = typeof refs;
const userSchema = {
type: 'object',
properties: {
id: { $ref: 'https://example.com/schemas/Id' },
notes: {
type: 'array',
items: { $ref: 'https://example.com/schemas/Note' },
},
},
required: ['id', 'notes'],
} as const satisfies JSONSchema7;
// Create a type with preset References
export type MySchemaType<S extends JSONSchema7> = SchemaType<S, GetRefs<Refs>>;
type User = MySchemaType<typeof userSchema>;
IsResponseをtrueにすると、defaultを持つプロパティがrequired扱いになります。
検証・成形後の値を表すときに使えます。
If IsResponse is set to true, properties with default are treated as required.
It can be used to represent a value after verification and molding.
const s = {
type: 'object',
properties: {
foo: { type: 'string', default: 'foo' },
hoge: { type: 'string' }
},
required: [],
} as const satisfies JSONSchema7;
type Req = SchemaType<typeof s, [], false>;
/**
* type Req = {
* foo?: string | undefined;
* hoge?: string | undefined;
* }
*/
type Res = SchemaType<typeof s, [], true>;
/**
* type Res = {
* foo: string;
* hoge?: string | undefined;
* }
*/
objectのpropertiesで、プロパティをas unknown as X
と書いて型X
で上書きすると、SchemaType
はその上書きされた型を返します。
ただし、X
がextends NonNullable<JSONSchema7>
でJSONSchema7として認識されてしまう場合はうまく動きません。
If you overwrite a property with type X
in the properties of an object by writing as unknown as X
, SchemaType
will return the overwritten type.
However, if X
is recognized as JSONSchema7 with extends NonNullable<JSONSchema7>
, it will not work.
type X = {
values: X[];
};
const s = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: {
type: 'object',
} as unknown as X,
},
required: ['foo', 'bar'],
} as const satisfies JSONSchema7;
type S = SchemaType<typeof s, []>;
/**
* type S = {
* foo: string;
* bar: X;
* }
*/
-
type: 'null'
-
type: 'string'
-
type: 'number'
,type: 'integer'
-
type: 'enum'
-
type: 'null'
-
type: Array<JSONSchema7TypeName>
-
additionalProperties
-
not
-
if
,then
,else
-
dependentRequired
,dependentSchemas
- Reading an array of global references
-
$defs
($defs in nested places will be ignored.) -
$ref
to $def and global references - Circular reference
$ref
(If the $ref target is an object or an array, the item will be no longerrequired
.) -
$dynamicRef
-
$anchor
,$dynamicAnchor
It is not possible to reference $defs
from parent to child or schema to schema.
-
allOf
-
oneOf
-
anyOf
- anyOf of object corresponds only to the anyOf branch of required.
@types/json-schema
ライブラリの型に準拠しています。
requiredが一つもないと型エラーが起きません。
objectに対してanyOfを使う場合、anyOfの中でpropertiesを定義しないこと。
ajvのバリデーションが効かないため。(SchemaTypeもそのように作られており、objectのanyOf内のpropertiesは捨てられます)
misskey-dev/misskey#10082
テキストhogeおよびfugaについて、片方を必須としつつ両方の指定もありうる場合:
export const schema = {
type: 'object',
properties: {
hoge: { type: 'string', minLength: 1 },
fuga: { type: 'string', minLength: 1 },
},
anyOf: [
{ required: ['hoge'] },
{ required: ['fuga'] },
],
} as const;
type: string
のとき、formatにdate
,date-time
が指定されていた場合はDate
、binary
の場合はRelativeIndexable<number>
となります。
string
に変換したい場合はSerialized<T>
、string | Date
のように両方を許容・推測したい場合はWeakSerialized<T>
でラップします。
import type { SchemaType, JSONSchema7, Serialized, WeakSerialized } from 'schema-type';
const schema = {
type: 'string',
format: 'date-time',
} as const satisfies JSONSchema7;
type D = SchemaType<typeof schema>; // Date
type SD = Serialized<D>; // string
type WSD = WeakSerialized<D> // string | Date