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

如何为TypeScript中动态生成方法的Shiinobi类添加类型定义?

解决TypeScript无法识别动态生成类方法的问题

要让TypeScript识别动态添加的类方法,核心是让TS能推断出这些方法的具体名称和类型,以下是可行的实现方案:

步骤1:固定命令数组的类型

首先给COMMANDS添加as const断言,让TypeScript推断出数组中每个元素的具体字符串字面量类型,而非宽泛的string类型:

const COMMANDS = [
    "get-myanimelist-staff-urls",
    "get-myanimelist-anime-explicit-genres",
    "get-myanimelist-anime-genres",
    "get-myanimelist-anime-themes"
    // ...其他命令
] as const;

步骤2:定义类型映射工具

创建辅助类型,将连字符格式的命令名转换为下划线格式的方法名,并生成对应方法的类型:

// 把连字符替换为下划线的递归类型
type ReplaceDashes<S extends string> = S extends `${infer P}-${infer R}` 
    ? `${P}_${ReplaceDashes<R>}` 
    : S;

// 生成所有动态方法的类型
type ShiinobiCommand = typeof COMMANDS[number];
type ShiinobiMethods = {
    // 每个命令对应一个async方法,接收可选id参数,返回Promise
    [Cmd in ShiinobiCommand as ReplaceDashes<Cmd>]: (id?: string | number) => Promise<unknown>;
};

步骤3:通过工厂函数生成类型安全的实例

使用工厂函数合并基础类和动态方法类型,避免手动声明每个方法:

class ShiinobiBase {
    // 原私有spawn方法保持不变
    async #spawn(options: { command: string; id?: string | number }) {
        // 这里写你的spawn逻辑,比如调用外部服务等
        return {};
    }

    // 生成所有动态方法的辅助函数
    #buildMethods() {
        const methods: Partial<ShiinobiMethods> = {};
        COMMANDS.forEach((command) => {
            const methodName = command.replaceAll("-", "_") as keyof ShiinobiMethods;
            methods[methodName] = async (id?: string | number) => {
                return this.#spawn({ command, id });
            };
        });
        return methods;
    }

    // 暴露给外部的创建入口
    static create(): ShiinobiBase & ShiinobiMethods {
        const instance = new ShiinobiBase();
        return Object.assign(instance, instance.#buildMethods()) as ShiinobiBase & ShiinobiMethods;
    }
}

步骤4:类型安全地使用实例

调用工厂函数创建实例后,TypeScript就能自动识别所有动态生成的方法,不会再抛出错误:

async function useShiinobi() {
    const shiinobi = ShiinobiBase.create();
    // 这里有完整的类型提示,无TS错误
    const staffUrls = await shiinobi.get_myanimelist_staff_urls("123");
    const genres = await shiinobi.get_myanimelist_anime_genres(456);
}

备选方案:类内手动声明方法类型

如果不想用工厂函数,也可以在类内通过declare关键字手动声明每个动态方法的类型,配合类型断言确保赋值安全:

class Shiinobi implements ShiinobiMethods {
    constructor() {
        COMMANDS.forEach((command) => {
            const methodName = command.replaceAll("-", "_") as keyof ShiinobiMethods;
            this[methodName] = async (id?: string | number) => {
                return this.#spawn({ command, id });
            };
        });
    }

    // 声明所有动态方法的类型,让TS识别它们
    declare get_myanimelist_staff_urls: (id?: string | number) => Promise<unknown>;
    declare get_myanimelist_anime_explicit_genres: (id?: string | number) => Promise<unknown>;
    declare get_myanimelist_anime_genres: (id?: string | number) => Promise<unknown>;
    declare get_myanimelist_anime_themes: (id?: string | number) => Promise<unknown>;
    // ...其他命令对应的声明

    async #spawn(options: { command: string; id?: string | number }) {
        // 原spawn逻辑
        return {};
    }
}

// 使用方式不变
async function test() {
    const shiinobi = new Shiinobi();
    const res = await shiinobi.get_myanimelist_staff_urls();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:58:10