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

如何用TypeScript泛型编写可扩展、可维护且DRY的树形库类型?

解决方案:可扩展、可维护的LinkMap泛型类型

TL;DR

我需要在库中定义如下结构的类型,要求具备可扩展性、可维护性且符合DRY原则:

const myProjectLinks: LinkMap<Region, Platform> = {
  global: {       // 区域
    ios: 'a',     // 平台
    android: 'b',
    huawei: 'c',
  },
  us: {
    ios: 'd',
  },
};

问题背景

我正准备将组件提取到库中,其中包含复杂类型。最终对象结构如上,但当前的LinkMap类型与项目强绑定,直接硬编码了区域和平台列表:

export enum LinkPlatform {
  Ios = 'ios',
  Android = 'android',
  Huawei = 'huawei',
}

export enum LinkRegion {
  Global = 'global',
  Us = 'us',
}

export type LinkMap = {
  [key in LinkRegion]?: {
    [key in LinkPlatform]?: string;
  };
};

存在以下痛点:

  • 代码重复:枚举键名与字符串值内容重复,仅大小写不同
  • 无法安全重命名:IDE无法自动同步修改字符串值的所有引用
  • 扩展性差:增删区域或平台必须修改库代码,无法由项目自主控制

已尝试的方案及问题

我试过泛型、字面量类型等方案,但都存在缺陷:

泛型+字面量类型

存在代码重复,部分内容无法自动重命名:

// 库侧代码
type LinkMap<Env extends string, Store extends string> = {
  [Key in Env]: {
    [Key in Store]?: string;
  };
};

// 项目侧代码
// 只能重命名枚举键,无法自动同步修改值,也没有定义提示
const enum LinkRegion { 
  Global = 'global',
  Us = 'us',
}

// 无法自动重构字符串值的所有引用
type LinkPlatform = 'ios' | 'android' | 'huawei';

// 类型安全但上述问题未解决
const myProjectLinks: LinkMap<LinkRegion, LinkPlatform> = {
  global: {
    ios: '',
    android: '',
    huawei: '',
  },
  us: {
    ios: '',
  },
};

基于对象类型的方案

存在大量无用的any类型,类型提示缺失:

// 库侧代码
type LinkMap<Region extends { [Key in keyof Region]: any }, Platform extends string> = {
  [Key in keyof Region]: {
    [Key in Region]?: string;
  };
};

// 项目侧代码
type LinkRegion = {
  global: any; // 无用的any,无实际作用也无类型提示
  us: any;
};

// ...

最终解决方案

核心思路是让库只提供通用的泛型类型定义,将区域、平台的具体定义完全交予项目侧,同时保证类型安全与IDE可操作性。

库侧通用类型定义

// 库中仅定义通用泛型,不绑定具体业务值
export type LinkMap<
  Region extends string,
  Platform extends string
> = Partial<Record<Region, Partial<Record<Platform, string>>>>;

// 可选:提供辅助函数,简化对象创建并自动推导类型
export function createLinkMap<
  R extends string,
  P extends string
>(links: LinkMap<R, P>): LinkMap<R, P> {
  return links;
}

项目侧使用方式

项目侧可通过两种方式定义区域和平台,均支持IDE自动重命名:

方式1:字符串枚举(推荐)

枚举的键与值绑定,IDE支持一键重命名所有引用:

import { LinkMap, createLinkMap } from 'your-library';

// 项目自定义区域枚举
export enum LinkRegion {
  Global = 'global',
  Us = 'us',
  // 新增区域直接在此添加,无需修改库
}

// 项目自定义平台枚举
export enum LinkPlatform {
  Ios = 'ios',
  Android = 'android',
  Huawei = 'huawei',
  // 新增平台同理
}

// 直接指定类型
const myProjectLinks: LinkMap<LinkRegion, LinkPlatform> = {
  [LinkRegion.Global]: {
    [LinkPlatform.Ios]: 'a',
    [LinkPlatform.Android]: 'b',
    [LinkPlatform.Huawei]: 'c',
  },
  [LinkRegion.Us]: {
    [LinkPlatform.Ios]: 'd',
  },
};

// 或用辅助函数自动推导类型(可选)
const myProjectLinks = createLinkMap({
  [LinkRegion.Global]: {
    [LinkPlatform.Ios]: 'a',
    [LinkPlatform.Android]: 'b',
    [LinkPlatform.Huawei]: 'c',
  },
  [LinkRegion.Us]: {
    [LinkPlatform.Ios]: 'd',
  },
});

方式2:字面量类型联合

若不想使用枚举,字面量类型联合同样支持IDE重命名:

import { LinkMap } from 'your-library';

// 项目自定义区域字面量类型
export type LinkRegion = 'global' | 'us';

// 项目自定义平台字面量类型
export type LinkPlatform = 'ios' | 'android' | 'huawei';

// 使用类型约束
const myProjectLinks: LinkMap<LinkRegion, LinkPlatform> = {
  global: {
    ios: 'a',
    android: 'b',
    huawei: 'c',
  },
  us: {
    ios: 'd',
  },
};

方案优势

  • 无代码重复:枚举或字面量直接定义所需字符串,无需重复书写
  • IDE友好:支持一键重命名所有相关引用,避免手动修改遗漏
  • 完全可扩展:项目侧可自由增删区域/平台,无需改动库代码
  • 符合DRY原则:库只提供通用逻辑,业务定义由项目自主控制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:58:11