name: 单数或数组模式 description: 用于接受单个项目或数组的函数模式。在创建CRUD操作、批量处理API或工厂函数时使用,应灵活处理一个或多个输入。 metadata: author: epicenter version: ‘1.0’
单数或数组模式
接受单个项目和数组,在顶部进行归一化,统一处理。
快速参考
function create(itemOrItems: T | T[]): Promise<Result<void, E>> {
const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
// ... 实现在items数组上工作
}
结构
- 接受
T | T[]作为参数类型 - 归一化 使用
Array.isArray()在函数顶部 - 所有逻辑 针对数组工作 — 一个代码路径
function createServer(clientOrClients: Client | Client[], options?: Options) {
const clients = Array.isArray(clientOrClients)
? clientOrClients
: [clientOrClients];
// 所有真实逻辑在这里,使用数组工作
for (const client of clients) {
// ...
}
}
命名约定
| 参数 | 归一化变量 |
|---|---|
recordingOrRecordings |
recordings |
clientOrClients |
clients |
itemOrItems |
items |
paramsOrParamsArray |
paramsArray |
何时使用
适合:
- CRUD操作(创建、更新、删除)
- 批量处理API
- 接受依赖项的工厂函数
- 任何“对一个或多个执行此操作”的场景
跳过当:
- 单数与批量有不同的语义
- 返回类型显著不同
- 数组版本需要不同的选项
代码库示例
服务器工厂 (packages/server/src/server.ts)
function createServer(
clientOrClients: AnyWorkspaceClient | AnyWorkspaceClient[],
options?: ServerOptions,
) {
const clients = Array.isArray(clientOrClients)
? clientOrClients
: [clientOrClients];
// 所有服务器设置逻辑直接在这里
const workspaces: Record<string, AnyWorkspaceClient> = {};
for (const client of clients) {
workspaces[client.id] = client;
}
// ...
}
数据库服务 (apps/whispering/src/lib/services/isomorphic/db/web.ts)
delete: async (recordingOrRecordings) => {
const recordings = Array.isArray(recordingOrRecordings)
? recordingOrRecordings
: [recordingOrRecordings];
const ids = recordings.map((r) => r.id);
return tryAsync({
try: () => db.recordings.bulkDelete(ids),
catch: (error) => DbServiceErr({ message: `删除错误: ${error}` }),
});
},
查询突变 (apps/whispering/src/lib/query/isomorphic/db.ts)
delete: defineMutation({
mutationFn: async (recordings: Recording | Recording[]) => {
const recordingsArray = Array.isArray(recordings)
? recordings
: [recordings];
for (const recording of recordingsArray) {
services.db.recordings.revokeAudioUrl(recording.id);
}
const { error } = await services.db.recordings.delete(recordingsArray);
if (error) return Err(error);
return Ok(undefined);
},
}),
反模式
不要:为单数和数组分离函数
// 更难维护,用户必须记住两个API
function createRecording(recording: Recording): Promise<...>;
function createRecordings(recordings: Recording[]): Promise<...>;
不要:到处强制数组
// 对单个项目笨拙
createRecordings([recording]); // 丑陋
不要:在重载中重复逻辑
// 坏:逻辑重复
function create(item: T) {
return db.insert(item); // 重复
}
function create(items: T[]) {
return db.bulkInsert(items); // 不同代码路径
}
// 好:单一实现
function create(itemOrItems: T | T[]) {
const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
return db.bulkInsert(items); // 一个代码路径
}
参考
- 完整文章 — 更多示例的详细解释