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

TypeScript中让Schema可选的惯用泛型实现方式探讨

背景

我开发了一个库,允许用户定义Schema,并根据定义返回自定义响应类型,以下是最简示例:

interface Item {
  id: string;
}

interface CardinalityDef {
  [objectType: string]: 'one' | 'many'
}

class Schema<Cardinality extends CardinalityDef> {
  constructor(public cardinality: Cardinality) {}
}

type ResponseOf<
  S extends Schema<any>, 
  K extends keyof S['cardinality']
> = S['cardinality'][K] extends 'one'
  ? Item
  : Item[];

class DB<S extends Schema<any>>{ 
  query<ObjectType extends keyof S['cardinality']>(objectType: ObjectType): ResponseOf<S, ObjectType> { 
    return 1 as any;
  }
}

function init<S extends Schema<any>>(schema: S): DB<S> {
  return 1 as any;
}

现在可以定义Schema并得到预期的响应类型:

const schema = new Schema({posts: 'many', author: 'one'})
const db = init(schema);
// 类型正确推导为 Item[]
const postsResponse = db.query('posts');
// 类型正确推导为 Item
const authorResponse = db.query('author');
目标:让Schema可选

希望用户无需提供Schema即可使用:

const db = init(); // 不传入schema

若未提供Schema,所有查询响应应返回Item[]:

const postsResponse: Item[] = db.query('posts');
const authorResponse: Item[] = db.query('author');
方案1:IsAny类型检查

将schema参数设为可选,更新ResponseOf类型:

function init<S extends Schema<any>>(schema?: S): DB<S> {
  return 1 as any;
}
type IsAny<T> = 0 extends (1 & T) ? true : never;
type ResponseOf<
  S extends Schema<any>, 
  K extends keyof S['cardinality']
> = IsAny<S['cardinality']> extends true
  ? Item[] 
  : S['cardinality'][K] extends 'one' 
    ? Item 
    : Item[];

此方案可正常工作,但存在疑问:

  • db被类型化为Schema<any>,但实际无Schema,不符合预期
  • 需在ResponseOf中显式检查any,感觉违背TS设计思路
方案2:Schema | undefined

显式处理undefined情况:

function init<S extends Schema<any> | undefined>(schema?: S): DB<S> {
  return 1 as any;
}

该方案也存在缺点:

  • 需在整个系统中传递| undefined类型
  • 未提供Schema时,TS未将S细化为严格的undefined
问题与讨论

哪种方案更符合TypeScript惯用风格?是否有其他实现可选Schema的更好方法?我倾向于默认Schema类型并显式IsAny检查,理由是无需传递undefined类型且能细化类型,欢迎各位建议。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:57:19