json-schema-to-typescript
json-schema-to-typescript copied to clipboard
Provide option to generate inline types instead of named interfaces
Currently, library generating named interfaces, enums, types, for root schema and for nested types, when possible (name = schema.title || schema.$id || keyNameFromDefinition).
e.g. for
{
"properties": {
"food": {
"type": "object",
"title": "food",
"properties": {
"tasty": {"type": "boolean"}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
it renders
export interface MySchema {
food?: Food
}
export interface Food {
tasty?: boolean
}
I propose to add support for forceGenerateInlineType:true option, which for above schema will generate
{
food?: {
tasty?: boolean;
};
}
We need this to because we want to form an object with inline types:
typeFromSchema1: ${genType(schema1)},
typeFromSchema2: ${genType(schema2)},
and for this json-schema-to-typescript should return type which could be inlined.
https://github.com/bcherny/json-schema-to-typescript/pull/460
This pr is poc implementation.
We need this to because we want to form an object with inline types:
Could you explain why you want this, and why you couldn't just reference the emitted name (MySchema) instead?
The problem is that inline emission would break for schemas with cyclical references (eg).
I'm working on a tool that parses an OpenAPI spec and generates TypeScript for a dummy server. For example, the code I'm working on right now takes this:
openapi: 3.0.0
paths:
/complex-types:
get:
responses:
default:
content:
"*/*":
schema:
type: object
properties:
name:
type: string
age:
type: number
required:
- name
additionalProperties: false
And produces this:
export type HTTP_GET = () => { body: { name: string; age?: number; } };
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
Right now I'm stripping out the parts I don't want.
async function jsonSchemaToTypeScript(schema) {
const typeScript = await compile(schema, "RemoveMe", {
bannerComment: "",
});
return typeScript
.replace("export type RemoveMe = ", "")
.replace("export interface RemoveMe ", "")
.slice(0, -1)
.replaceAll(/\s+/gu, " ");
}
I guess what you're suggesting is I do something like this instead.
export interface SomeCalculatedName = { name: string; age?: number; };
export type HTTP_GET = () => { body: SomeCaculatedName };
And now that I've written it out I think I've convinced myself this is the way to go. (I literally just started using this library a couple of hours ago. 😅 )
However I think it would be great if there was an additional synchronous function that outputs an inline type. I'd be okay with it not having some of the bells and whistles like circular references and $refs. It could either throw an error when it encounters one of those cases or output any. It would make simple use cases a lot more straightforward.
@bcherny our usecase - platform where we providing this types does not support named declarations. It's expected inline object type, because it's creating a big map of types, smth like
type Mapping = {
'providedKey1': ${providedType1},
....
}
It's a limitation of a platform, and I don't know how often this is a usecase of others.