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

如何将动态生成的字符串转换为TypeScript代码以构建resolvers对象?

动态生成GraphQL Resolvers的可行方案

嘿,你的思路其实是可行的,但在TypeScript环境下直接通过字符串转代码的方式需要注意安全和类型问题,而且还有更稳妥的替代方案,我给你详细梳理下:

1. 直接用eval实现你的思路(不推荐)

你想通过构造字符串再转成代码的方式是可以实现的,比如用eval执行拼接后的代码字符串:

// 假设你的links数据已经定义
const links = [{ id: '1', url: 'example.com' }, /* 其他数据 */];

// 从查询结果生成的函数字符串
const strCode = `info: () => 'teeeeest', feed: () => links, get: (root, args) => { let indLink = links.findIndex((el) => el.id === args.id); return links[indLink]; }`;

// 拼接成完整的resolvers对象代码
const fullResolverCode = `({ Query: { ${strCode} } })`;

// 执行代码得到resolvers
const resolvers = eval(fullResolverCode);

⚠️ 注意:这种方式非常不推荐,原因有两个:

  • 安全风险:eval会执行任意传入的代码,如果strCode的来源不可信(比如用户输入、第三方接口),很容易引发代码注入攻击。
  • 类型丢失:TypeScript无法对eval生成的代码做类型检查,你的resolvers会失去类型提示,不利于后续维护。

2. 推荐:用对象动态构建(安全且保留类型)

其实resolvers本质就是一个普通的JavaScript对象,完全可以通过动态添加属性的方式来构建,不需要用字符串转代码的方式。这种方法既安全,又能保留TypeScript的类型支持:

示例代码:

// 假设这是你从查询结果获取到的resolver配置(可以是任何结构化数据,不一定是函数)
const resolverConfigs = [
  {
    name: 'info',
    // 直接定义函数逻辑,或者根据查询结果动态生成
    handler: () => 'teeeeest'
  },
  {
    name: 'feed',
    handler: () => links
  },
  {
    name: 'get',
    handler: (root: unknown, args: { id: string }) => {
      const indLink = links.findIndex(el => el.id === args.id);
      return links[indLink];
    }
  }
];

// 用reduce动态构建Query对象
const Query = resolverConfigs.reduce((acc, config) => {
  acc[config.name] = config.handler;
  return acc;
}, {} as Record<string, (...args: any[]) => any>);

// 最终的resolvers对象
const resolvers = { Query };

如果需要更精确的类型,可以给resolverConfigs定义接口,比如:

interface ResolverConfig {
  name: string;
  handler: (root: unknown, args: Record<string, any>) => any;
}

const resolverConfigs: ResolverConfig[] = [/* 配置内容 */];

这样TypeScript就能自动推断Query和resolvers的类型,开发时能获得完整的类型提示。

3. 特殊场景:只能拿到函数体字符串的情况

如果你的查询结果只能拿到函数体的字符串(比如从数据库存储的字符串),可以用Function构造函数来生成函数,但同样要注意安全问题:

// 假设从查询结果拿到的是函数名和函数体字符串
const resolverFunctionData = [
  { name: 'info', body: `return 'teeeeest';` },
  { name: 'feed', body: `return links;` },
  { name: 'get', body: `let indLink = links.findIndex(el => el.id === args.id); return links[indLink];` }
];

const Query = resolverFunctionData.reduce((acc, item) => {
  // 创建函数,传入需要的参数(root, args),并让函数捕获当前作用域的links
  acc[item.name] = (root: unknown, args: { id: string }) => {
    // 用Function构造函数执行函数体,传入需要的变量
    return new Function('links', 'args', item.body)(links, args);
  };
  return acc;
}, {} as Record<string, (...args: any[]) => any>);

const resolvers = { Query };

⚠️ 注意:这种方式依然存在安全风险,只有当item.body的来源绝对可信时才能使用。

总结

  • 优先选择对象动态构建的方式,安全、高效且保留TypeScript类型支持。
  • 尽量避免使用eval或Function构造函数,除非你能完全确保字符串来源的安全性,并且接受类型丢失的代价。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:18:24