You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript导出Hono路由typeof类型时导入为any的问题求助

如何正确导出Hono路由生成的typeof复杂类型供其他包使用?

我在TypeScript模块中通过typeof导出Hono路由生成的复杂类型,但其他包导入该类型时始终显示为any。相关代码与配置如下:

问题代码示例

控制器文件 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';

项目tsconfig配置

{
    "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
    }
}

问题现象

  • 本地编辑器中能看到route的完整类型:
    Hono<{
        Bindings: Binding;
    }, Schema<"post", "/", {
        json: {
            lastname?: string | undefined;
            avatar?: string | undefined;
            id: string;
            username: string;
            firstname: string;
        };
    }, ReturnType>>
    
  • 但tsc生成的声明文件中route被推断为any:
    export declare const route: any;
    export type CreateProfileType = typeof route;
    
  • 手动给route添加显式类型注解后,导出的类型恢复正常。

解决方案

1. 调整TypeScript编译配置

开启类型声明生成,并根据项目需求调整isolatedModules:

{
  "compilerOptions": {
    // ... 其他原有配置
    "declaration": true,          // 启用类型声明文件生成
    "declarationMap": true,       // 生成类型映射,方便调试
    "isolatedModules": false      // 若项目不需要独立模块编译,可关闭此选项
  }
}

isolatedModules会强制单文件编译,导致TypeScript无法完整保留Hono路由的复杂泛型类型,关闭后能让编译器完整推断路由类型。

2. 显式提取路由Schema类型

避免直接依赖typeof route,先从Hono类型工具中提取路由的Schema定义:

// controller/createProfile.ts
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
import type { Hono, Schema } from 'hono';

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()),
});

// 显式定义路由的Schema类型
type CreateProfileRouteSchema = Schema<
  "post",
  "/",
  { json: z.infer<typeof createProfileBody> },
  Profile // 替换为你的路由返回类型
>;

// 给路由方法传入预定义的Schema类型
const route = app.post<CreateProfileRouteSchema>(
  '/', 
  zValidator('json', createProfileBody), 
  async c => {
    // ... 路由逻辑
  }
);

export type CreateProfileType = typeof route;

这种方式让TypeScript明确识别路由的泛型参数,生成声明文件时不会丢失类型信息。

3. 手动添加路由类型注解(快速修复)

如你已经尝试的那样,直接给route变量添加完整的类型注解:

const route: Hono<
  { Bindings: Binding },
  Schema<'post','/',
    { json: z.infer<typeof createProfileBody> },
    Profile
  >
> = app.post('/', zValidator('json', createProfileBody), async c => {
  // ... 路由逻辑
});

export type CreateProfileType = typeof route;

4. 验证Hono类型完整性

如果开启了skipLibCheck,可尝试临时关闭它,检查是否是Hono类型定义冲突导致的问题。若关闭后类型恢复正常,建议更新Hono到最新版本,确保其类型定义完整兼容当前TypeScript版本。


验证方法

修改配置或代码后,重新执行编译命令,查看生成的.d.ts文件,确认route的类型不再是any,而是完整的Hono泛型类型。此时其他包导入CreateProfileType即可获取正确的类型信息。

内容的提问来源于stack exchange,提问作者JonasLevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 15:39:22