重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
single-or-array-pattern by epicenterhq/epicenter
npx skills add https://github.com/epicenterhq/epicenter --skill single-or-array-pattern接受单个项目或数组,在顶层进行标准化,统一处理。
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) {
// ...
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 参数 | 标准化后的变量 |
|---|---|
recordingOrRecordings | recordings |
clientOrClients | clients |
itemOrItems | items |
paramsOrParamsArray | paramsArray |
适用场景:
避免使用:
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) => DbError.MutationFailed({ cause: 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); // 单一代码路径
}
每周安装量
56
代码仓库
GitHub 星标数
4.3K
首次出现
2026 年 1 月 20 日
安全审计
安装于
claude-code49
gemini-cli49
opencode49
cursor48
codex48
antigravity45
Accept both single items and arrays, normalize at the top, process uniformly.
function create(itemOrItems: T | T[]): Promise<Result<void, E>> {
const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
// ... implementation works on items array
}
T | T[] as the parameter typeArray.isArray() at the top of the functionfunction createServer(clientOrClients: Client | Client[], options?: Options) {
const clients = Array.isArray(clientOrClients)
? clientOrClients
: [clientOrClients];
// All real logic here, working with the array
for (const client of clients) {
// ...
}
}
| Parameter | Normalized Variable |
|---|---|
recordingOrRecordings | recordings |
clientOrClients | clients |
itemOrItems | items |
paramsOrParamsArray | paramsArray |
Good fit:
Skip when:
packages/server/src/server.ts)function createServer(
clientOrClients: AnyWorkspaceClient | AnyWorkspaceClient[],
options?: ServerOptions,
) {
const clients = Array.isArray(clientOrClients)
? clientOrClients
: [clientOrClients];
// All server setup logic directly here
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) => DbError.MutationFailed({ cause: 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);
},
}),
// Harder to maintain, users must remember two APIs
function createRecording(recording: Recording): Promise<...>;
function createRecordings(recordings: Recording[]): Promise<...>;
// Awkward for single items
createRecordings([recording]); // Ugly
// BAD: Logic duplicated
function create(item: T) {
return db.insert(item); // Duplicated
}
function create(items: T[]) {
return db.bulkInsert(items); // Different code path
}
// GOOD: Single implementation
function create(itemOrItems: T | T[]) {
const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
return db.bulkInsert(items); // One code path
}
Weekly Installs
56
Repository
GitHub Stars
4.3K
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code49
gemini-cli49
opencode49
cursor48
codex48
antigravity45
Genkit JS 开发指南:AI 应用构建、错误排查与最佳实践
10,800 周安装
NotebookLM 研究助手技能 - 基于 Google NotebookLM 的文档智能查询与自动化管理工具
2 周安装
baoyu-slide-deck:AI幻灯片生成器,一键将Markdown转为专业演示文稿
2 周安装
宝玉信息图生成器:AI驱动,20种布局×17种风格自由组合,一键生成专业信息图
2 周安装
知识漫画生成器 - AI驱动漫画创作工具,支持多种画风与基调组合
2 周安装
Ant Design 在 Next.js 中的企业级 UI 开发指南 - 快速集成与 CRUD 模板
2 周安装
单向门/双向门决策框架:亚马逊贝佐斯决策分类工具,提升决策速度与质量
2 周安装