如何让TypeScript识别execute方法的命令参数为查询列表的键
如何让TypeScript在调用execute方法时自动提示namedQueries的键?
我有一个工厂函数InitializeQuery,它返回一个Query对象,相关代码如下:
query.ts
class Query<T> { private queryList: Record<string, string> async init(url: string, queries: Record<string, string>) { this.queryList = queries } execute(command: string extends keyof this.queryList, parameter: Record<string, string> ): Promise<T[]> { } } export async function InitializeQuery<T>( url: string, queries: Record<string, string> ) { const queryObject = new Query<T>(); await queryObject.init(url, queries) return queryObject; }
table.d.ts(表结构定义)
type ItemType = { id: string, name: string, weight: number, createdBy: string }
index.ts(使用示例)
import { InitializeQuery } from './query.js'; const itemNamedQueries: Record<string, string> = { "selectById": "SELECT * FROM Table WHERE id = :id", "selectByName": "SELECT * FROM Table WHERE name = :name", "findAll": "SELECT * FROM Table" } const query = await InitializeQuery<ItemType>( 'mysql://user:pass@localhost/database', itemNamedQueries); const result = await query.execute("selectById", {id: 25})
目前代码运行正常,但我经常在输入itemNamedQueries的键时打错字。希望调用execute方法时,按下Ctrl+Space后,IDE能识别command参数是传入的namedQueries的键,并给出候选提示列表。
我在VSCode中做了如下测试,但并未生效:
const test: Record<string, string> = { FindAll: "SELECT * FROM TableData", Find: "SELECT * FROM TableData WHERE id = :id", } as const function fn<C extends keyof typeof test>(command: C) { } fn()
解决方案
核心是保留传入的queries对象的键字面量类型,而不是用Record<string, string>抹除具体的键信息。
1. 修改Query类,新增泛型参数保留键类型
给Query类添加一个泛型参数Q,用来约束queryList的键和execute方法的command参数:
class Query<T, Q extends string> { private queryList: Record<Q, string>; async init(url: string, queries: Record<Q, string>) { this.queryList = queries; } execute(command: Q, parameter: Record<string, string>): Promise<T[]> { // 这里写你的执行逻辑 return Promise.resolve([]); } }
2. 修改InitializeQuery工厂函数,推断键类型
让工厂函数自动推断传入的queries的键类型,而不是固定为Record<string, string>:
export async function InitializeQuery<T, Q extends string>( url: string, queries: Record<Q, string> ) { const queryObject = new Query<T, Q>(); await queryObject.init(url, queries); return queryObject; }
3. 使用时去掉冗余类型声明,保留字面量类型
去掉itemNamedQueries的Record<string, string>类型声明,并用as const让TypeScript精确保留键的字面量类型:
import { InitializeQuery } from './query.js'; // 去掉Record<string, string>,用as const保留字面量类型 const itemNamedQueries = { "selectById": "SELECT * FROM Table WHERE id = :id", "selectByName": "SELECT * FROM Table WHERE name = :name", "findAll": "SELECT * FROM Table" } as const; const query = await InitializeQuery<ItemType>( 'mysql://user:pass@localhost/database', itemNamedQueries); // 此时调用execute会自动提示selectById、selectByName、findAll const result = await query.execute("selectById", {id: "25"});
测试代码的问题修正
你之前的测试代码失效,是因为给test指定了Record<string, string>类型,覆盖了as const的字面量类型推断。去掉这个类型声明即可:
const test = { FindAll: "SELECT * FROM TableData", Find: "SELECT * FROM TableData WHERE id = :id", } as const; function fn<C extends keyof typeof test>(command: C) { } fn(); // 现在IDE会自动提示FindAll和Find
内容的提问来源于stack exchange,提问作者Magician
相关产品推荐
相关产品推荐

