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

如何定义字段级泛型的TypeScript类型SomeType?

问题描述

现有如下TypeScript类型定义:

type SomeType<Prop, Model> = {
  [value: string]: {
    loadMany: (ids: readonly Prop[]) => readonly Model[];
    getProp: (ids: readonly Prop[]) => readonly Model[]
  }
}

需要让Prop和Model泛型参数作用于字段级别而非SomeType类型级别,即实现如下结构:

class User {
  constructor(public id: number, public username: string) {}
}

const args: SomeType = {
  id: {
    loadMany: (ids: readonly number[]) => new Array(ids.length).fill(new User(0, 'sup')), 
    getProp: (user: User) => user.id,
  },
  username: {
    loadMany: (ids: readonly string[]) => new Array(ids.length).fill(new User(0, 'sup')), 
    getProp: (user: User) => user.username,
  }
}

请重新定义SomeType以满足需求。


解决方案

根据需求,我们可以通过映射类型结合泛型约束实现字段级别的泛型控制,以下是几种不同场景的最优实现:

方案1:统一Model的严格约束(推荐)

如果所有字段的Model是同一个类型(比如示例中的User),可以基于Model的字段结构自动推导类型,确保loadMany的入参类型与getProp的返回值类型完全匹配:

// 单个字段的配置类型
type FieldConfig<Model, Prop> = {
  loadMany: (ids: readonly Prop[]) => readonly Model[];
  getProp: (model: Model) => Prop;
}

// 基于Model生成字段映射的SomeType
type SomeType<Model> = {
  [K in keyof Model]?: FieldConfig<Model, Model[K]>;
}

使用示例:

class User {
  constructor(public id: number, public username: string) {}
}

const args: SomeType<User> = {
  id: {
    loadMany: (ids: readonly number[]) => new Array(ids.length).fill(new User(0, 'sup')), 
    getProp: (user) => user.id, // 自动推导返回值为number
  },
  username: {
    loadMany: (ids: readonly string[]) => new Array(ids.length).fill(new User(0, 'sup')), 
    getProp: (user) => user.username, // 自动推导返回值为string
  }
};

这种方案的类型安全性最高,TypeScript会自动校验每个字段的类型一致性。

方案2:支持多Model的灵活配置

如果不同字段的Model类型不同,可以通过泛型对象定义每个字段的Prop和Model,再通过映射类型生成最终结构:

type FieldConfig<Prop, Model> = {
  loadMany: (ids: readonly Prop[]) => readonly Model[];
  getProp: (model: Model) => Prop;
}

type SomeType<FieldMap extends Record<string, { Prop: any; Model: any }>> = {
  [K in keyof FieldMap]: FieldConfig<FieldMap[K]['Prop'], FieldMap[K]['Model']>;
}

使用示例:

class User {
  constructor(public id: number, public username: string) {}
}

class Post {
  constructor(public slug: string, public title: string) {}
}

// 显式指定每个字段的Prop和Model类型
const args = {
  userId: {
    loadMany: (ids: readonly number[]) => new Array(ids.length).fill(new User(0, 'sup')), 
    getProp: (user: User) => user.id,
  },
  postSlug: {
    loadMany: (slugs: readonly string[]) => new Array(slugs.length).fill(new Post('test', 'Hello')), 
    getProp: (post: Post) => post.slug,
  }
} satisfies SomeType<{
  userId: { Prop: number; Model: User };
  postSlug: { Prop: string; Model: Post };
}>;

方案3:无预定义的松散约束

如果不需要严格的类型校验,仅需要支持字段级别的泛型参数,可以直接在方法上定义泛型:

type SomeType = {
  [key: string]: {
    loadMany: <Prop, Model>(ids: readonly Prop[]) => readonly Model[];
    getProp: <Prop, Model>(model: Model) => Prop;
  };
}

这种方式灵活性最高,但缺乏类型校验,适合快速原型开发场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:51:32