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

Type error when generate declartion file for a exported schema #274

Closed
fengkx opened this issue Nov 8, 2022 · 7 comments
Closed

Type error when generate declartion file for a exported schema #274

fengkx opened this issue Nov 8, 2022 · 7 comments

Comments

@fengkx
Copy link

fengkx commented Nov 8, 2022

When I export the generted schema object with Type.Optional and have declaration: true in tsconfig. I got this error.

 Exported variable 'data' has or is using name 'Modifier' from external module ".../node_modules/@sinclair/typebox/typebox" but cannot be named.

I try to add

import { Modifier } from '@sinclair/typebox';
export { Modifier };

Memtioned in this issue, but error is still there.
Because I want to export the Modifier, I try to add this declartion.

declare module '@sinclair/typebox' {
  export type Modifier: typeof Modifier;
}

Then I got another error

Exported type alias 'Modifier' has or is using private name ''.ts(4081)

What could I do to get rid of this?

@sinclairzx81
Copy link
Owner

@fengkx Hi. You may need to export everything from TypeBox as many of the types (and symbols) are used for composition and inference (and TypeScript will need to know about all types in order to infer correctly)

export * from '@sinclair/typebox'

Does this help?

@fengkx
Copy link
Author

fengkx commented Nov 8, 2022

Does this help?

No, It still produce the same TS4023 error.

.../a.ts:37:7 - error TS4023: Exported variable 'config' has or is using name 'Modifier' from external module "/Users/fengkx/..../node_modules/@sinclair/typebox/typebox" but cannot be named.

I found this microsoft/TypeScript#37888 issue. It seems to be the same case, Modifier is a symbol here

@sinclairzx81
Copy link
Owner

sinclairzx81 commented Nov 8, 2022

@fengkx I can't seem to reproduce the issue.

modifier.ts

import { Modifier } from '@sinclair/typebox'

export { Modifier }

index.ts

import { Modifier } from './modifier'

console.log(Modifier)

compiled with

npx tsc index.ts --declaration # compiles without error

As TypeBox already exports everything (including symbols, types, interfaces and the TypeBuilder), I don't believe there is much else the library can do to make things more public (also, re-exporting types and symbols is supported by the library (and used quite a bit in mono repository setups) so not sure what is causing the problem). I think I would need to see a full reproduction of the TS4023 error to provide more assistance.

Are you able to provide a simplified reproduction of the issue?

@fengkx
Copy link
Author

fengkx commented Nov 8, 2022

I make a reproduction https://github.com/fengkx/typebox-ts4023-reproduction

When I make this reproduction, I found it related to

class TypeBuilder extends TypeboxTypeBuilder {
  Slot<T extends Except<SchemaOptions, 'x-index'>>(
    options?: T
  ): TOptional<TUnsafe<React.ReactNode>> & { type: 'slot' } {
    return {
      type: 'slot',
      ...Type.Optional(T.Unsafe<React.ReactNode>(options)),
    };
  }
}

When I use this method, I got the TS4023 error

const data = Type.Object({
  contentSlot: Type.Slot({
    type: 'slot',
  }),
});

clone the repo, npm install then tsc
got

image

@sinclairzx81
Copy link
Owner

You could express Type.Slot() in the following way. I believe the inner ...Type.Optional(T.Unsafe<React.ReactNode>(options)), is the cause of the problem where the T in Type.Unsafe<T> requires the modifier for optional inference.

class TypeBuilder extends TypeboxTypeBuilder {
  public Slot(options: SchemaOptions = {})  {
    return Type.Unsafe<React.ReactNode & { type: 'slot'}>({
      type: 'slot', // <- this needs to be validate-able 
      ...options,
    })
  }
}

export const Type = new TypeBuilder();

Just a side note, this may not be the most ideal way to use TypeBox as React.ReactNode cannot be validated using JSON schema. Usually when creating an unsafe type, you would define a custom schema that would be understood by a JSON Schema validator (like AJV), and usually ONLY for values that can be serialized to JSON (noting that React.ReactNode cannot be serialized to JSON)

The following would be the intended use of Type.Unsafe()

// creates a nullable type understood by OpenAPI 3.1 and below.
function Nullable<T extends TSchema>(schema: T) {
  return Type.Unsafe<Static<T> | null>({  // <- this is the static type to infer
    ...schema, nullable: true             // <- this is the schema understood by Ajv
   })
}

The following would be a more typical usage of TypeBox when working with React. Note that there is no requirement to infer React library types.

import { Type, Static } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

export type HeaderProperties = Static<typeof HeaderProperties>
export const HeaderProperties = Type.Object({
   header: Type.String({ default: 'header text' }),
   subheader: Type.String({ default: 'subheader text' })
})

export function HeaderComponent(props: HeaderProperties) {
   return (
      <div className='header'>
         <h1>{props.header}</h1>
         <h2>{props.subheader}</h2>
      </div>
   )
}

export function App() {
  return <div className='app'>
     <HeaderComponent {...Value.Create(HeaderProperties)} />
  </div>
}

Hope this helps!

@fengkx
Copy link
Author

fengkx commented Nov 9, 2022

Thanks you for detail explaination. This does solve the problem.

@fengkx fengkx closed this as completed Nov 9, 2022
@ghost
Copy link

ghost commented Jun 19, 2024

You may need to export everything from TypeBox...

I have a shared library which contains all of my schemas and shared types that I use in frontend and backend packages and I decided to list typebox as a peer dependency in that library. So far everything is working for me.

(I found this issue because I thought I was having a problem with typebox schema types not resolving when exported from a shared library. The actual problem turned out to be incorrect (aliased) paths in my generated declaration files, now fixed with tsc-alias. So I'm just leaving this note for anyone else who might happen onto this.)

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