Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types not resolving correctly after 2.9.2 #183

Open
hamanuha opened this issue Dec 23, 2023 · 3 comments
Open

Types not resolving correctly after 2.9.2 #183

hamanuha opened this issue Dec 23, 2023 · 3 comments

Comments

@hamanuha
Copy link

Hi,

first of all I want to say thank you for this great library!

I use it to share typed api routes between backend and frontend.
Basically I define a contract using json schemas. This is then used for the validation and for the types on the backend and for creating the queries for the frontend.

Unfortunately upgrading to 2.12.0 or 3.0.0 breaks my code.
I heavily simplified the example below to show the issue. Some types seem to be not needed but this is due to the simplification.

If I define the schema externally for initContract then this works with the newer versions as well.
But my inline schema for the params property only works with version 2.9.2.

Any idea what causes this behaviour?
I would like to continue using inline schema definitions.

Types with 2.9.2
types-2-9-2

Types with 2.12.0
types-2-12-0

Simplified example

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

// Simplified version
type ContractRoute = {
  params: JSONSchema
  query: JSONSchema
}

type Contract = {
  [key: string]: ContractRoute
}

type ProcessContract<T extends Contract> = {
  [K in keyof T]: T[K]
}

const initContract = <TRouter extends Contract>(routes: ProcessContract<TRouter>): TRouter => routes

type ContractRouteImplementation<T extends ContractRoute> = () => {
  handler: (request: { Params: FromSchema<T['params']>; Query: FromSchema<T['query']> }) => void
}

type ServerObj<T extends Contract> = {
  [TKey in keyof T]: ContractRouteImplementation<T[TKey]>
}

type InitialisedServer<T extends Contract> = {
  contract: T
  routes: ServerObj<T>
}

const initServer = <T extends Contract>(contract: T, routes: ServerObj<T>): InitialisedServer<T> => ({
  contract,
  routes,
})

// Example
const externSchema = {
  type: 'object',
  properties: {
    str: { type: 'string' },
  },
  required: ['str'],
  additionalProperties: false,
} as const

const contract = initContract({
  demo: {
    params: {
      type: 'object',
      properties: {
        str: { type: 'string' },
      },
      required: ['str'],
      additionalProperties: false,
    } as const,
    query: externSchema,
  },
})

initServer(contract, {
  demo: () => ({
    handler: async (request) => {},
  }),
})
@ThomasAribart
Copy link
Owner

Hi @hamanuha and thanks for reaching out!

This seems to be related to #165, you can look at https://github.com/ThomasAribart/json-schema-to-ts/blob/main/documentation/FAQs/applying-from-schema-on-generics.md

This worked for me:

type ContractRouteImplementation<
  CONTRACT_ROUTE extends ContractRoute,
  PARAMS = FromSchema<CONTRACT_ROUTE["params"]>,
  QUERY = FromSchema<CONTRACT_ROUTE["query"]>,
> = () => {
  handler: (request: { Params: PARAMS; Query: QUERY }) => void;
};

@hamanuha
Copy link
Author

hamanuha commented Dec 27, 2023

Hi @ThomasAribart,

thanks for the hint. Unfortunately this does not work for me.
I am using typescript 5.3.3. Maybe it's related to some config values?

Would you mind sharing your tsconfig?

Edit:
When using your asConst function it works with both versions of the ContractRouteImplementation.
But only if I use as const as well.

const contract = initContract({
  demo: {
    params: asConst({
      type: 'object',
      properties: {
        str: { type: 'string' },
      },
      required: ['str'],
      additionalProperties: false,
    } as const),
    query: externSchema,
  },
})

Edit2:
When using the Narrow type from your package inside FromSchema it works also for the inline schema without having to use asConst

type ParamsFromSchema<T extends ContractRoute, TParams = Narrow<T['params']>> = TParams extends JSONSchema
  ? FromSchema<TParams>
  : never

@ThomasAribart ThomasAribart reopened this Dec 27, 2023
@hamanuha
Copy link
Author

Hey @ThomasAribart,

did you see my second edit?
Can I help with something to resolve this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants