JS TS 如何将重复代码重构为具有多种参数类型的高阶函数
JS TS how to refactor repetitive code into a higher order function with multiple param types
我一直想用打字稿将以下代码重构为高阶函数,以使其更清晰、更可重用,但我发现让它工作真的很有挑战性。
import { DocumentDefinition, FilterQuery, QueryOptions, UpdateQuery } from 'mongoose';
import TaskModel, { TaskDocument } from '../models/Task.model';
import { databaseResponseTimeHistogram } from '../utils/appmetrics';
export async function createTask(
input: DocumentDefinition<
Omit<TaskDocument, 'createdAt' | 'updatedAt' | 'taskId' | 'isCompleted'>
>
) {
const metricsLabels = { operation: 'createTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.create(input);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
export async function findTask(
query: FilterQuery<TaskDocument>,
options: QueryOptions = { lean: true }
) {
const metricsLabels = { operation: 'findTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.findOne(query, {}, options);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
export async function findAndUpdateTask(
query: FilterQuery<TaskDocument>,
update: UpdateQuery<TaskDocument>,
options: QueryOptions
) {
const metricsLabels = { operation: 'findTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.findOneAndUpdate(query, update, options);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
基本上我想用 try catch 块将整个指标功能重构为一个实用函数,允许使用相应的参数调用它,操作,TaskModel.method 和相应的参数将是 (输入)用于创建,(查询,{},选项)用于 findOne 和(查询,更新,选项)用于 findManyAndUpdate...
到目前为止,我 运行 在正确键入所有不同参数等方面遇到了困难。
所以基本上你想重构这部分:
try {
/* SOME OPERATION */
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
您可以将它包装在一个函数中,然后将 SOME OPERATION
作为参数传入:
function withTimer (label:string, operation:Function) {
const metricsLabels = { operation: label };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = operation();
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
现在你的函数可以重写为:
export async function createTask(
input: DocumentDefinition<
Omit<TaskDocument, 'createdAt' | 'updatedAt' | 'taskId' | 'isCompleted'>
>
) {
return withTimer('createTask',
() => TaskModel.create(input)
);
}
export async function findTask(
query: FilterQuery<TaskDocument>,
options: QueryOptions = { lean: true }
) {
return withTimer('findTask',
() => TaskModel.findOne(query, {}, options)
);
}
export async function findAndUpdateTask(
query: FilterQuery<TaskDocument>,
update: UpdateQuery<TaskDocument>,
options: QueryOptions
) {
return withTimer('findTask',
() => TaskModel.findOneAndUpdate(query, update, options)
);
}
使用 higher-order 函数的关键是意识到您可以将代码的 不常见 部分包装在函数中以传递给代码的公共部分。
我一直想用打字稿将以下代码重构为高阶函数,以使其更清晰、更可重用,但我发现让它工作真的很有挑战性。
import { DocumentDefinition, FilterQuery, QueryOptions, UpdateQuery } from 'mongoose';
import TaskModel, { TaskDocument } from '../models/Task.model';
import { databaseResponseTimeHistogram } from '../utils/appmetrics';
export async function createTask(
input: DocumentDefinition<
Omit<TaskDocument, 'createdAt' | 'updatedAt' | 'taskId' | 'isCompleted'>
>
) {
const metricsLabels = { operation: 'createTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.create(input);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
export async function findTask(
query: FilterQuery<TaskDocument>,
options: QueryOptions = { lean: true }
) {
const metricsLabels = { operation: 'findTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.findOne(query, {}, options);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
export async function findAndUpdateTask(
query: FilterQuery<TaskDocument>,
update: UpdateQuery<TaskDocument>,
options: QueryOptions
) {
const metricsLabels = { operation: 'findTask' };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = TaskModel.findOneAndUpdate(query, update, options);
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
基本上我想用 try catch 块将整个指标功能重构为一个实用函数,允许使用相应的参数调用它,操作,TaskModel.method 和相应的参数将是 (输入)用于创建,(查询,{},选项)用于 findOne 和(查询,更新,选项)用于 findManyAndUpdate...
到目前为止,我 运行 在正确键入所有不同参数等方面遇到了困难。
所以基本上你想重构这部分:
try {
/* SOME OPERATION */
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
您可以将它包装在一个函数中,然后将 SOME OPERATION
作为参数传入:
function withTimer (label:string, operation:Function) {
const metricsLabels = { operation: label };
const timer = databaseResponseTimeHistogram.startTimer();
try {
const result = operation();
timer({ ...metricsLabels, success: 'true' });
return result;
} catch (err: any) {
timer({ ...metricsLabels, success: 'false' });
throw new Error(err.message);
}
}
现在你的函数可以重写为:
export async function createTask(
input: DocumentDefinition<
Omit<TaskDocument, 'createdAt' | 'updatedAt' | 'taskId' | 'isCompleted'>
>
) {
return withTimer('createTask',
() => TaskModel.create(input)
);
}
export async function findTask(
query: FilterQuery<TaskDocument>,
options: QueryOptions = { lean: true }
) {
return withTimer('findTask',
() => TaskModel.findOne(query, {}, options)
);
}
export async function findAndUpdateTask(
query: FilterQuery<TaskDocument>,
update: UpdateQuery<TaskDocument>,
options: QueryOptions
) {
return withTimer('findTask',
() => TaskModel.findOneAndUpdate(query, update, options)
);
}
使用 higher-order 函数的关键是意识到您可以将代码的 不常见 部分包装在函数中以传递给代码的公共部分。