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

如何在TypeScript中为派生类型添加新取值并维护相关类型映射?

如何在TypeScript中为派生类型添加新取值并维护相关类型映射?

嘿,看你这套TypeScript类型系统搭得有模有样的,但每次加新动物类型时是不是得改好几个地方?一会儿改枚举,一会儿改映射接口,稍不留神就漏改了?我来给你支个招,让新增类型的维护工作轻松不少。

先把你现有的代码贴出来,方便咱们对照着说:

interface CommonAnimalProps {
    common: {
        size: number, 
        weight: number,
        origin: string,
    }
}

interface DogProps extends CommonAnimalProps {
    name: string
}

interface CatProps extends CommonAnimalProps {
    furious: boolean
}

interface BirdProps extends CommonAnimalProps {
    canFly: boolean
}

export enum AnimalType {
    dog = "dog",
    cat = "cat",
    bird = "bird",
}

export interface AnimalTypeToAnimalPropsMap {
    [AnimalType.dog]: (DogProps)[],
    [AnimalType.cat]: (CatProps)[],
    [AnimalType.bird]: (BirdProps)[]
}

export type AllAnimalValues<T> = T[keyof T]
export type AllAnimalTypesArray = AllAnimalValues<AnimalTypeToAnimalPropsMap>
export type AllAnimalTypes = AllAnimalValues<AnimalTypeToAnimalPropsMap>[0]
export type AllAnimalTypesArrayDiscriminating = AllAnimalTypes[]

现有结构的维护痛点

目前你这套结构的问题很明显:新增动物类型时必须同步修改两处——既要在AnimalType枚举里加新值,又要在AnimalTypeToAnimalPropsMap里加对应的类型映射,万一漏改其中一处,类型系统就会出问题。

优化方案:用单一数据源驱动所有类型推导

咱们可以把「区分联合类型」作为单一可信数据源,让枚举、类型映射、数组类型都从这个联合类型自动推导。这样新增动物时,只需要加一个接口就行,其他所有类型都会自动更新。

优化后的代码是这样的:

interface CommonAnimalProps {
  common: {
    size: number, 
    weight: number,
    origin: string,
  }
}

// 每个动物接口都加一个唯一的type字面量属性,作为区分联合类型的标识
interface DogProps extends CommonAnimalProps {
  type: 'dog';
  name: string;
}

interface CatProps extends CommonAnimalProps {
  type: 'cat';
  furious: boolean;
}

interface BirdProps extends CommonAnimalProps {
  type: 'bird';
  canFly: boolean;
}

// 新增动物?只需要加这一个接口就行!
interface FishProps extends CommonAnimalProps {
  type: 'fish';
  waterType: 'fresh' | 'salt'; // 新增动物的专属属性
}

// 定义所有动物的区分联合类型——这就是咱们的单一数据源
type AllAnimalTypes = DogProps | CatProps | BirdProps | FishProps;

// 自动推导动物类型的字面量集合(代替原来的枚举,也可以转成枚举)
type AnimalType = AllAnimalTypes['type'];

// 自动推导类型到数组的映射,完全不用手动维护
type AnimalTypeToAnimalPropsMap = {
  [K in AnimalType]: Extract<AllAnimalTypes, { type: K }>[];
};

// 原来的工具类型可以大幅简化
type AllAnimalTypesArray = AllAnimalTypes[];
type AllAnimalTypesArrayDiscriminating = AllAnimalTypes[];

优化后的好处

  1. 新增类型超省心:只需要新增一个带type标识的接口,其他所有类型(包括AnimalType、映射类型、数组类型)都会自动同步更新,再也不用怕漏改
  2. 类型收窄贼方便:因为用了区分联合类型,你在处理动物实例时,TypeScript会自动根据type属性做类型收窄,不用手动类型断言:
    function feedAnimal(animal: AllAnimalTypes) {
      switch (animal.type) {
        case 'dog':
          console.log(`喂${animal.name}吃狗粮`); // 这里自动推断为DogProps
          break;
        case 'fish':
          console.log(`喂鱼吃饲料,水质要求:${animal.waterType}`); // 自动推断为FishProps
          break;
        // 其他动物类型同理
      }
    }
    
  3. 类型安全有保障:如果你的type标识写错了,TypeScript会直接报错,从源头避免错误

如果你还想用枚举

要是你习惯用枚举而不是字面量类型,也可以从推导出来的AnimalType字面量类型生成枚举,还能加个类型断言确保枚举值和字面量一致:

export enum AnimalType {
  Dog = 'dog',
  Cat = 'cat',
  Bird = 'bird',
  Fish = 'fish'
}

// 可选:检查枚举值是否和AnimalType字面量完全匹配,不匹配就报错
type AssertAnimalTypeMatches = AnimalType[keyof AnimalType] extends AnimalType ? true : never;

这样一来,你整个类型系统的维护成本就大大降低了,新增动物类型再也不用东改西改啦!

备注:内容来源于stack exchange,提问作者four-eyes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 15:13:03