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

如何避免TypeScript/JavaScript中DynamoDB操作的重复代码?

解决DynamoDB Scan/Query方法代码重复的问题

首先明确核心问题:DynamoDB.DocumentClient.ScanInput和QueryInput是TypeScript接口而非可实例化的类,编译后这些类型信息会被擦除,因此无法用instanceof判断参数类型——这就是你报错的原因,因为DocumentClient在运行时根本没有ScanInput/QueryInput这些构造函数属性。

以下是几种消除代码重复的可行方案:

方案1:提取通用执行函数,手动指定操作类型

直接把重复的逻辑抽成私有通用函数,通过传入操作类型('scan'或'query')来调用对应的客户端方法,最简洁直观:

import { DynamoDB } from 'aws-sdk';

class DBService {
  private static client = new DynamoDB.DocumentClient();

  // 通用执行逻辑
  private static async runOperation(
    params: DynamoDB.DocumentClient.ScanInput | DynamoDB.DocumentClient.QueryInput,
    operation: 'scan' | 'query'
  ) {
    try {
      const result = await this.client[operation](params).promise();
      return result.Items;
    } catch (err) {
      const opName = operation.charAt(0).toUpperCase() + operation.slice(1);
      throw new Error(`${opName} failed: ${(err as Error).message}`);
    }
  }

  // 保留原方法名,转发调用通用函数
  static async scanTable(params: DynamoDB.DocumentClient.ScanInput) {
    return this.runOperation(params, 'scan');
  }

  static async queryTable(params: DynamoDB.DocumentClient.QueryInput) {
    return this.runOperation(params, 'query');
  }
}

方案2:自定义类型守卫自动判断参数类型

利用两种输入参数的特征差异(QueryInput必须包含KeyConditionExpression字段,而ScanInput不需要),写一个自定义类型守卫来区分类型,无需手动传入操作标识:

import { DynamoDB } from 'aws-sdk';

class DBService {
  private static client = new DynamoDB.DocumentClient();

  // 自定义类型守卫:判断是否为QueryInput
  private static isQueryInput(
    params: DynamoDB.DocumentClient.ScanInput | DynamoDB.DocumentClient.QueryInput
  ): params is DynamoDB.DocumentClient.QueryInput {
    return 'KeyConditionExpression' in params;
  }

  // 通用执行逻辑
  private static async runOperation(
    params: DynamoDB.DocumentClient.ScanInput | DynamoDB.DocumentClient.QueryInput
  ) {
    try {
      const result = this.isQueryInput(params) 
        ? await this.client.query(params).promise() 
        : await this.client.scan(params).promise();
      return result.Items;
    } catch (err) {
      const opName = this.isQueryInput(params) ? 'Query' : 'Scan';
      throw new Error(`${opName} failed: ${(err as Error).message}`);
    }
  }

  // 保留原方法名
  static async scanTable(params: DynamoDB.DocumentClient.ScanInput) {
    return this.runOperation(params);
  }

  static async queryTable(params: DynamoDB.DocumentClient.QueryInput) {
    return this.runOperation(params);
  }
}

方案3:使用参数重载优化类型推断

如果希望调用通用函数时TypeScript能自动推断返回类型(虽然这里返回类型一致),可以用参数重载来明确不同输入对应的处理逻辑:

import { DynamoDB } from 'aws-sdk';

class DBService {
  private static client = new DynamoDB.DocumentClient();

  // 参数重载:明确不同输入的类型
  static async executeOperation(params: DynamoDB.DocumentClient.ScanInput): Promise<DynamoDB.DocumentClient.ItemList | undefined>;
  static async executeOperation(params: DynamoDB.DocumentClient.QueryInput): Promise<DynamoDB.DocumentClient.ItemList | undefined>;
  
  // 通用执行逻辑
  static async executeOperation(
    params: DynamoDB.DocumentClient.ScanInput | DynamoDB.DocumentClient.QueryInput
  ) {
    try {
      const result = 'KeyConditionExpression' in params 
        ? await this.client.query(params).promise() 
        : await this.client.scan(params).promise();
      return result.Items;
    } catch (err) {
      const opName = 'KeyConditionExpression' in params ? 'Query' : 'Scan';
      throw new Error(`${opName} failed: ${(err as Error).message}`);
    }
  }

  // 保留原方法名的话直接转发即可
  static async scanTable(params: DynamoDB.DocumentClient.ScanInput) {
    return this.executeOperation(params);
  }

  static async queryTable(params: DynamoDB.DocumentClient.QueryInput) {
    return this.executeOperation(params);
  }
}

关键说明

  • 不要用instanceof判断接口类型:TypeScript接口仅存在于编译阶段,运行时没有对应的构造函数,因此DynamoDB.DocumentClient.ScanInput不是一个可实例化的类,自然无法通过instanceof检查。
  • 三种方案各有优劣:方案1最易维护,方案2更自动化,方案3类型推断更严谨,可根据你的代码场景选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 13:50:45