如何避免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
相关产品推荐
相关产品推荐

