能否基于函数参数生成静态类型对象?TypeScript技术问询
基于动态字符串参数构建带Intellisense的静态类型Params对象
我原本以为这没法实现,但还是想确认一下。我尝试通过函数传入的字符串参数,为Intellisense创建一个静态类型的params对象,当前代码如下:
type Query = { _def: { params: Record<string, string> // 这里该怎么写? } params: (name: string) => Query; } const queryBuilder = (def: Query["_def"]): Query => { return { _def: def, params: (name) => { const innerDef = { ...def, params: { ...def.params, [name]: undefined as unknown as string // 这里只是用来保存类型 } } return queryBuilder(innerDef); } } } const c = queryBuilder({} as Query["_def"]); const d = c.params("hello").params("world"); d._def.params; // 希望Intellisense能提示hello和world const e: typeof c._def.params = {} // 希望抛出错误,提示hello和world是必填项
目前用Record<string, string>无法提供Intellisense提示或错误提示,也没法用const断言,因为没有可断言的具体内容。有没有其他可行的方法?
解决方案
要实现动态累积参数名并生成静态类型,需要让Query和queryBuilder支持泛型,用泛型追踪已添加的参数名称:
// 用泛型P追踪已添加的参数名集合,默认是空集合 type Query<P extends string = never> = { _def: { // 映射类型:P中的每个字符串都是必填的string类型键 params: { [K in P]: string } } // params方法接收新参数名N,返回包含P|N集合的新Query类型 params: <N extends string>(name: N) => Query<P | N>; } // 构建函数用泛型P约束参数和返回值类型 const queryBuilder = <P extends string = never>(def: Query<P>["_def"]): Query<P> => { return { _def: def, params: (name) => { const innerDef = { ...def, params: { ...def.params, [name]: "" as string // 占位值,仅用于类型累积 } } // 类型断言让TS识别新的参数集合 return queryBuilder(innerDef as Query<P | typeof name>["_def"]); } } } // 初始调用时参数集合为空 const c = queryBuilder({ params: {} } as Query["_def"]); // 每次调用params都会累积参数名到泛型中 const d = c.params("hello").params("world"); d._def.params; // 现在Intellisense会提示hello和world两个属性 // 此处会抛出类型错误,因为{}缺少hello和world必填项 const e: typeof d._def.params = {}
关键说明
- 泛型
P用来持续追踪所有通过params方法添加的参数名称,每次调用都会把新参数名N合并到集合中。 - 将
params的类型改为映射类型{ [K in P]: string },让TypeScript把P中的每个字符串识别为必填键,从而提供智能提示和类型校验。 - 构建函数中的类型断言是为了让TypeScript正确推断新的泛型参数,确保类型累积逻辑生效。
内容的提问来源于stack exchange,提问作者Anthony Ma
相关产品推荐
相关产品推荐

