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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:40:21