ThomasAribart / json-schema-to-ts

Infer TS types from JSON schemas 📝
MIT License
1.4k stars 30 forks source link

JSDoc sees type as never when marking some properties as required #185

Closed dariocravero closed 5 months ago

dariocravero commented 5 months ago

Hi,

I'm trying to use the library with JSDoc and it almost works :D.

See this screenshot (TS to the left, JS with JSDoc to the right):

CleanShot 2024-01-24 at 13 59 12@2x

Here's a gist with both files.

The definitions are very similar, the first ones don't specify required and the second ones do.

The inferred schema for the version without required seems to be equivalent when applied to a value. However, when the version that has required is used valueRequired2 in JS, the TypeScript extension in VSCode fails with the following error:

Type '{ input: { x: number; }; }' is not assignable to type 'never'.ts(2322)
const valueRequired2: never
@type — {import('json-schema-to-ts').FromSchema}

This is all with TypeScript 5.3.3, forcing VSCode to use the version of TS from node_modules like this in .vscode/settings.json:

{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true
}

This is the current jsconfig.json:

{
  "compilerOptions": {
    "checkJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noStrictGenericChecks": false,
    "moduleResolution": "node"
  },
  "exclude": ["node_modules"]
}

I tried toggling both strict and noStrictGenericChecks on and off as suggested in the readme but it makes no difference.

I understand this might not be a problem with the library itself but more so with the combination of JSDoc and everything else. Figured I'd ask anyway if you may have any clues as to what could be going on?

Thanks!

ThomasAribart commented 5 months ago

Hi @dariocravero and thanks for the issue, I never tried using FromSchema in JSDocs before.

My guess is that it comes from the as const statement missing. The @satisfies seems to partially narrow the type of your schemas, which is already great (so "object" is kept as "object" and not widened as string), but it doesn't narrow the required keyword value (it is inferred as string[]) which leads to FromSchema being unable to infer required properties.

Can you add some kind of /** @as const **/ ?

dariocravero commented 5 months ago

Thanks for the hint @ThomasAribart! I think tried that but it didn't work, however, looking up online I came across this post and the last answer suggests using @type {const} which works if the object is wrapped in () 🤷‍♂️ 😬 .

Eg if I add @type {const} before the object's declaration, it doesn't work:

/**
 * @type {const}
 * @satisfies {import('json-schema-to-ts').JSONSchema}
 */
const schemaRequired2 = {
  type: 'object',
  required: ['input'],
  additionalProperties: false,
  properties: {
    input: {
      type: 'object',
      additionalProperties: false,
      required: ['x'],
      properties: {
        x: { type: 'number' },
      },
    },
  },
}

However, if the definition is wrapping the object in parenthesis and move the type definition right before the group as suggested on the last comment of that post, it works!

const schemaRequired2 =
  /** @type {const} @satisfies {import('json-schema-to-ts').JSONSchema}*/ ({
    type: 'object',
    required: ['input'],
    additionalProperties: false,
    properties: {
      input: {
        type: 'object',
        additionalProperties: false,
        required: ['x'],
        properties: {
          x: { type: 'number' },
        },
      },
    },
  })

Then when I do:

/** @type {import('json-schema-to-ts').FromSchema<typeof schemaRequired2>} */
const valueRequired2 = {
  input: {
    x: 2,
  },
}

I get this as expected:

const valueRequired2: {
    input: {
        x: number;
    };
}

I realise that this is what asConst intends to do in a way but its type definition in JSDocs doesn't seem to work as intended. I tried a few different things but I'm not too clear on how to do hack it out tbh. I'm more than happy with the inline comment solution from above though 😆. I submitted that as a PR on the docs here in case it's useful for others https://github.com/ThomasAribart/json-schema-to-ts/pull/187.

Thanks again! Loving this library, it makes it sooooo much easier to reason about the schema and gets rid of a lot of extra work! 👏

ThomasAribart commented 5 months ago

Awesome! Thanks!