TypeScript中如何通过扩展包扩展NPM核心包的类型?
解决方案
问题出在你使用type定义核心类型,而TypeScript中类型别名(type)不支持声明合并,只有接口(interface)支持;同时当前的扩展方式会直接覆盖核心类型,而非新增分支。以下是修复步骤:
1. 核心包调整:改用接口+基础联合类型
将核心包的ParcelTracking拆分为基础接口和联合类型,方便扩展包添加新的类型分支:
// package/shipping/index.d.ts // 基础接口定义通用属性 export interface BaseParcelTracking { provider: string; } // 导出联合类型,初始仅包含基础类型 export type ParcelTracking = BaseParcelTracking;
2. 扩展包调整:扩展联合类型
每个扩展包通过模块扩展,向核心包的ParcelTracking联合类型中添加专属类型:
UPS扩展包
// package/@shipping/ups-provider/index.d.ts declare module "shipping" { // 定义UPS专属追踪类型,继承基础接口并指定provider固定值 export interface UpsParcelTracking extends BaseParcelTracking { provider: "UPS"; ups_tracking_number: string; } // 将UPS类型合并到核心联合类型 export type ParcelTracking = ParcelTracking | UpsParcelTracking; }
FedEx扩展包
// package/@shipping/fedex-provider/index.d.ts declare module "shipping" { export interface FedexParcelTracking extends BaseParcelTracking { provider: "FEDEX"; fedex_tracking_number: string; fedex_estimated_delivery_date: string; } export type ParcelTracking = ParcelTracking | FedexParcelTracking; }
3. 应用代码:利用自动类型推断
此时TypeScript会根据provider的具体值自动推断对应类型,无需额外断言:
// my-app/index.ts import { ParcelTracking } from "shipping"; import "@shipping/ups-provider"; import "@shipping/fedex-provider"; function updateOrderShipment(orderId: string, tracking: ParcelTracking) { // ... 存储到数据库 } async function onParcelSent(orderId: string, webhookData: any) { if (webhookData.caller === "UPS") { await updateOrderShipment(orderId, { provider: "UPS", ups_tracking_number: webhookData.tracking_number, }); // 类型校验通过 return; } if (webhookData.caller === "FEDEX") { await updateOrderShipment(orderId, { provider: "FEDEX", fedex_tracking_number: webhookData.tracking_number, fedex_estimated_delivery_date: webhookData.estimated_delivery_date, }); // 类型校验通过 return; } }
关键原理
- 接口继承:扩展包专属类型继承核心基础接口,保证通用属性一致性。
- 联合类型合并:通过模块扩展机制,TypeScript自动将各扩展包的类型合并到核心
ParcelTracking联合类型中。 - 区分联合类型:以
provider的固定字符串值作为类型标识,让TypeScript自动推断对应类型的专属属性,避免类型错误。
内容的提问来源于stack exchange,提问作者maxime
相关产品推荐
相关产品推荐

