question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

When the schema is typed as JSONSchema, FromSchema<typeof schema> is never

See original GitHub issue

Hello,

The newly created type from a schema is never if the schema is typed as JSONSchema.

Let me demonstrate with an object example provided in the README.MD

When typed as JSONSchema

In the following example, I denote objectSchema variable as JSONSchema, and it is indeed helpful when I am typing properties. However, when I declare Object using objectSchema, its value is never.

import type { FromSchema, JSONSchema } from "json-schema-to-ts"

const objectSchema: JSONSchema = {
      type: "object",
      properties: {
            foo: { type: "string" },
            bar: { type: "number" },
      },
      required: ["foo"],
} as const;
type Object = FromSchema<typeof objectSchema>;

Here you can see the type when I hover over Object: image


When NOT typed as JSONSchema

The very same example, however, works when I don’t annotate objectSchema.

import type { FromSchema } from "json-schema-to-ts"

const objectSchema = {
      type: "object",
      properties: {
            foo: { type: "string" },
            bar: { type: "number" },
      },
      required: ["foo"],
} as const;
type Object = FromSchema<typeof objectSchema>;

image

I’m really not sure why, and I’m confused as FromSchema is already defined as a generic expecting JSONSchema type, however, resulting in never when a value typed as JSONSchema.

export declare type FromSchema<S extends JSONSchema> = Resolve<ParseSchema<DeepWriteable<S>>>;

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
ThomasAribartcommented, Oct 10, 2021

Hello @omer-to !

I understand it is confusing, but this is the expected behavior.

A constant (objectSchema here) can only have one type. If you don’t assign one to it, TS will infer it from its definition. The as const statement forces it to be as narrow as possible. Notice the difference:

const objectSchema = {
      type: "object",
      properties: {
            foo: { type: "string" },
            bar: { type: "number" },
      },
      required: ["foo"],
}

type testWidened = typeof objectSchema
// => { type: string, properties: { foo: string, bar: string }, required: string[] }
// The type is not narrow, for instance, the hard string "number" is widened as a general string

const objectSchema = {
      type: "object",
      properties: {
            foo: { type: "string" },
            bar: { type: "number" },
      },
      required: ["foo"],
} as const

type testNarrow = typeof objectSchema
// => { type: "object" , properties: { foo: "string", bar: "number" }, required:["foo"] }
// (I omitted the readonly part for the sake of simplicity)
// The type is narrow, for instance "number" is kept as the hard string "number"


const objectSchema: JSONSchema = {
      type: "object",
      properties: {
            foo: { type: "string" },
            bar: { type: "number" },
      },
      required: ["foo"],
} as const;

type testAssigned = typeof objectSchema
// => JSONSchema
// The assigned type JSONSchema overrides the inferred type from TS

In order for FromSchema to be able to infer the valid type from a schema, the input schema type needs to be as narrow as possible. Otherwise, it won’t be able to apply any logic to it. For instance, if any type keyword value is widened as a general string or as a union of hard strings ("object" | "array" | ...), FromSchema won’t have enough information on the schema to operate. FromSchema<JSONSchema> will not return anything, the JSONSchema definition is too large to infer anything.

However, that doesn’t prevent it from enforcing that the input schema type should follow a certain shape, and that means extending a certain type. That’s the meaning of the S extends JSONSchema that you found in the definition. This allows S (which should be the narrow type { type: "object" , properties: { foo: "string", bar: "number" }, required:["foo"] }) to be validated against JSONSchema, while not being strictly equal to JSONSchema.

I hope it makes things a bit clearer. The main takeaway is that you cannot both assign JSONSchema and apply FromSchema to the same const simultaneously. Cheers !

0reactions
ThomasAribartcommented, Nov 22, 2022

Yup 😃 Gonna add it to the docs !

Read more comments on GitHub >

github_iconTop Results From Across the Web

Allow the insertion of errors from outside JSONSchema ...
import Form, { validateJsonSchema, mergeErrorSchema } from "react-jsonschema-form"; const schema = { type: "object", properties: { pass1: ...
Read more >
JSON Schema in 5 minutes
JSON Schema is both the name given to the project and the artefact (A JSON Schema) that defines the required validation. The validation...
Read more >
Home - react-jsonschema-form documentation - Read the Docs
react-jsonschema-form is meant to automatically generate a React form based on a JSON Schema. It is a major component in the kinto-admin project....
Read more >
I need to have some fields in ui-schema which do not exist in ...
A little confused here.A UI schema is basically an object literal providing information on how the form should be rendered, while the JSON...
Read more >
JSON Type Definition | Ajv JSON schema validator
Unlike JSON Schema, JTD does not allow defining values that can take one of several types, but they can be defined as nullable...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found