如何集中为非JS文件(如SQL)声明TypeScript类型?
集中式为SQL文件配置TypeScript类型声明
针对你开发Vite插件加载.sql文件时的类型声明需求,这里提供一种集中式管理且支持不同SQL文件自定义返回类型的方案:
方案概述
通过基础模块声明+集中类型映射+可选自动生成脚本的组合,既满足每个SQL文件的专属类型需求,又避免分散的.d.ts文件,实现类型集中管理。
1. 基础模块声明
在项目的types目录下创建sql.d.ts,让TypeScript识别所有.sql模块:
// types/sql.d.ts declare module "*.sql" { // 定义SQL导出的基础结构,根据你的插件实际输出调整 type BaseSqlQuery<T = unknown> = { sql: string; // 示例:假设你的插件提供执行方法,返回Promise<T> execute(): Promise<T>; }; const query: BaseSqlQuery; export default query; }
2. 集中维护类型映射
在types目录下创建sql-types.ts,统一管理所有SQL文件的返回类型映射:
// types/sql-types.ts // 1. 定义各个SQL查询的返回类型(可关联项目中已有的DTO/接口) export type UserListResult = { id: number; username: string; email: string; }; export type OrderStatsResult = { totalOrders: number; pendingOrders: number; }; // 2. 创建文件路径到返回类型的映射 export interface SqlTypeMap { "./src/sql/get-user-list.sql": UserListResult; "./src/sql/get-order-stats.sql": OrderStatsResult; // 按实际SQL文件路径逐一添加 }
3. 类型关联与自动推断
为了让TypeScript自动识别每个SQL文件的专属类型,你可以选择以下两种方式:
方式A:使用类型助手函数(推荐)
在项目工具目录创建sql-utils.ts,封装导入逻辑并绑定类型:
// src/utils/sql-utils.ts import type { SqlTypeMap } from "../../types/sql-types"; // 导入SQL文件时自动匹配对应类型 export function loadSql<T extends keyof SqlTypeMap>(filePath: T) { return require(filePath).default as { sql: string; execute(): Promise<SqlTypeMap[T]>; }; }
使用示例:
// 业务代码中导入SQL import { loadSql } from "./utils/sql-utils"; const userListQuery = loadSql("./src/sql/get-user-list.sql"); // userListQuery.execute() 的返回类型自动推断为 UserListResult
方式B:扩展模块声明(进阶)
修改sql.d.ts,利用TypeScript的模块扩展能力关联类型映射:
// types/sql.d.ts import type { SqlTypeMap } from "./sql-types"; declare module "*.sql" { type BaseSqlQuery<T = unknown> = { sql: string; execute(): Promise<T>; }; // 从导入路径匹配映射中的类型 type CurrentPath = `${string}.sql`; type QueryResult = CurrentPath extends keyof SqlTypeMap ? SqlTypeMap[CurrentPath] : unknown; const query: BaseSqlQuery<QueryResult>; export default query; }
这种方式无需额外工具函数,直接导入SQL文件即可自动匹配类型(需确保路径完全匹配SqlTypeMap中的键)。
4. 可选:自动生成类型映射脚本
如果SQL文件较多,手动维护SqlTypeMap麻烦,可以写一个Node脚本自动生成:
// scripts/generate-sql-types.js const fs = require("fs"); const path = require("path"); const sqlRootDir = path.resolve(__dirname, "../src/sql"); const outputFile = path.resolve(__dirname, "../types/sql-types.ts"); // 遍历所有SQL文件 const sqlFiles = fs.readdirSync(sqlRootDir, { recursive: true }) .filter(file => file.endsWith(".sql")) .map(file => path.join("./src/sql", file)); // 生成类型映射内容 let typeContent = `// 自动生成,请勿手动修改 // 如需自定义返回类型,请修改下方对应的接口定义 `; // 为每个SQL文件生成默认类型(可根据实际需求扩展,比如从SQL注释提取类型) sqlFiles.forEach(filePath => { const typeName = filePath.replace(/\.\/src\/sql\/|\.sql/g, "").replace(/[-/]/g, "") + "Result"; typeContent += `export type ${typeName} = unknown;\n`; }); typeContent += `\nexport interface SqlTypeMap {\n`; sqlFiles.forEach(filePath => { const typeName = filePath.replace(/\.\/src\/sql\/|\.sql/g, "").replace(/[-/]/g, "") + "Result"; typeContent += ` "${filePath}": ${typeName};\n`; }); typeContent += `}\n`; // 写入文件 fs.writeFileSync(outputFile, typeContent);
运行脚本后,sql-types.ts会自动生成所有SQL文件的类型映射,你只需修改其中的unknown为实际返回类型即可。
内容的提问来源于stack exchange,提问作者Jindong Zhang
相关产品推荐
相关产品推荐

