I have one Typescript module that exports a complex type created with the typeof
operator, like below:
// controller/createProfile.ts
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
const createProfileBody = z.object({
id: z.string({
required_error: 'Id is required.',
}),
username: z.string({
required_error: 'User name is required.',
}),
firstname: z.string({
required_error: 'First name is required',
}),
lastname: z.optional(z.string()),
avatar: z.optional(z.string()),
});
const route = app.post('/', zValidator('json', createProfileBody), async c => {
...
});
export type CreateProfileType = typeof route;
// types.d.ts
export * from './controller/createProfile';
The type of route
is this complex type:
Hono<{
Bindings: Binding;
}, Schema<"post", "/", {
json: {
lastname?: string | undefined;
avatar?: string | undefined;
id: string;
username: string;
firstname: string;
};
}, ReturnType>>
It's similar to tRPC
since it creates the type for the createProfile
endpoint.
I now want to import the CreateProfileType
from a different module but its type is always any
when importing the type.
This is my tsconfig
for the module that exports the type:
{
"include": ["src/**/*.ts"],
"compilerOptions": {
"baseUrl": "src",
"target": "esnext",
"module": "esnext",
"lib": ["esnext"],
"resolveJsonModule": true,
"moduleResolution": "node",
"allowJs": true,
"checkJs": false,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
In my package.json
of the exporting module I have specified the types
field to my types.d.ts
file.
One weird think I have noticed is, when the type of CreateProfileType
is just a simple string
, the imported type is not any
but string
and it works as expected. So my guess would be that this is somehow linked to exporting a type which is just an alias to a type from a different package in my case hono
.
Is it possible to export the typeof route
to make it accessible for different packages?
Edit
When I generate a declaration file with tsc
I get the following output. So somehow the type of the route is lost.
export declare const route: any;
export type CreateProfileType = typeof route;
What I also noticed is, when I manually specify the type of route
like below, the exported type is the correct on and not any
const route: Hono<
{
Bindings: Binding;
},
Schema<'post','/',
{
json: {
lastname?: string | undefined;
avatar?: string | undefined;
id: string;
username: string;
firstname: string;
};
},Profile
>
> = app.post('/', zValidator('json', createProfileBody), async c => {
...
});
I just found the answer to my question.
The reason the exported type was
any
was because I set thebaseURL
tosrc
in mytsconfig
. After switching to absolute imports the type was correct, I think for some reason typescript was not able to locate theReturnType
andBinding
type that was used by the inferred type ofroute
.