如何基于可选依赖是否安装实现TypeScript条件类型动态调整
实现方案
TS 本身是静态编译工具,无法直接感知运行时的依赖安装状态,但可以通过兜底模块声明+导入类型探测+条件类型的组合实现需求,类型会自动根据用户是否安装了xyz包适配。
具体实现步骤
- 先添加兜底模块声明
在你包的全局类型文件(比如index.d.ts)中添加xyz包的兜底类型声明,当用户未安装xyz时会命中这个兜底逻辑:
// 兜底声明:用户未安装xyz时生效,导出的所有类型均为never declare module "xyz" { // 这里要和实际xyz包导出的类型结构对齐,不存在的类型全部设为never即可 export type Test = never; }
- 编写依赖存在判断的工具类型
// 探测是否存在可用的xyz包:如果导入的xyz类型是never说明未安装,否则说明已安装 type HasXyz = typeof import("xyz") extends { Test: never } ? false : true;
- 定义适配的返回值类型
type BaseType = "foo" | "bar"; // 从xyz包导入实际需要的类型,未安装时会拿到never type AdditionalType = import("xyz").Test | "baz"; // 自动适配的返回值类型 type DoThingReturn = HasXyz extends true ? AdditionalType : BaseType;
- 编写函数实现(注意同步添加运行时判断,和类型逻辑对齐)
function doThing(): DoThingReturn { // 运行时判断xyz是否存在 const hasXyzRuntime = (() => { try { require.resolve("xyz"); return true; } catch { return false; } })(); if (hasXyzRuntime) { // 已安装xyz的逻辑,可以返回AdditionalType范围内的值 return "baz"; } else { // 未安装xyz的逻辑,只能返回BaseType范围内的值 return "foo"; } }
注意事项
- 要求用户环境的TS版本不低于4.5,且
tsconfig.json中的moduleResolution配置为node16/nodenext/bundler,避免导入类型探测失效 - 若
xyz包没有自带类型声明,你需要自行把@types/xyz加入你包的可选依赖,保证安装了xyz的用户可以拿到正确的类型 - 如果需要更严格的校验,可以将兜底的
xyz模块声明放在单独的.d.ts文件中,通过package.json的typesVersions配置做条件导出,进一步避免类型冲突
内容的提问来源于stack exchange,提问作者CEbbinghaus
相关产品推荐
相关产品推荐

