# @clipboard-health/contract-core 中文文档

规范地址：https://npmcn.com/package/%40clipboard-health/contract-core/

版本：4\.6\.15
npm 元数据更新时间：2026-11-05T04:55:20.150Z
中文译文更新时间：2026-11-10T01:49:33.222Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40clipboard-health/contract-core
原文对照：https://npmcn.com/package/%40clipboard-health/contract-core/?lang=original
项目主页：https://github.com/ClipboardHealth/core-utils#readme
源码仓库：https://github.com/ClipboardHealth/core-utils

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：50.1 kB，63 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：zod ^3
- 首次发布：2024-10-22T19:15:08.552Z
- 最新版本发布：2026-11-05T04:55:19.983Z
- 近 30 天下载量：124066（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：490（近 12 个月 391 个）

## 中文简介

为剪贴板的合同共享Zod计划.

## 安装

```sh
npm install @clipboard-health/contract-core
```

也可以使用：`pnpm add @clipboard-health/contract-core`、`yarn add @clipboard-health/contract-core`、`bun add @clipboard-health/contract-core`

## README

# @ 剪贴板- 健康/ 合同核心

为剪贴板的合同共享Zod计划.

## 目录

-   [安装](https://npmcn.com/package/%40clipboard-health/contract-core/#readme-install)
-   [使用量](https://npmcn.com/package/%40clipboard-health/contract-core/#readme-usage)
    -   [Zod 计划](https://npmcn.com/package/%40clipboard-health/contract-core/#readme-zod-schemas)
-   [地方发展指挥部](https://npmcn.com/package/%40clipboard-health/contract-core/#readme-local-development-commands)

## 安装

```bash
npm install @clipboard-health/contract-core
```

## 使用量

### Zod 计划

#### 逗号分隔阵列计划

`commaSeparatedArray(itemSchema)` 验证以逗号分隔的字符串或数组输入,并将其规范化为已键入数组。 为共享合同所设计,服务器接收逗号分隔的查询字符串,客户端通过打入的数组.

```ts
// z.input  → string | string[]
// z.output → string[]
commaSeparatedArray(nonEmptyString).optional();

// z.input  → string | ("CNA" | "RN" | "LVN")[]
// z.output → ("CNA" | "RN" | "LVN")[]
commaSeparatedArray(requiredEnum(["CNA", "RN", "LVN"]));

// z.input  → string | string[]
// z.output → string[]  (each validated as ObjectId)
commaSeparatedArray(objectId);

// z.input  → string | (string | Date)[]
// z.output → Date[]
commaSeparatedArray(dateTimeSchema());
```

由所有合同核心计划 和enum助手组成 替换 `z.preprocess(splitString, z.array(...))` 与适当的 `z.input` 输入 `splitString` 模式去除输入类型到 `unknown`) (中文(简体) ).

#### 日期时间计划

`dateTimeSchema()` 验证严格的 ISO-8601 日期时间字符串并将其转换为 `Date` 对象。 与 `z.coerce.date()`,它拒绝像时代数字和只使用日期字符串这样的松散输入。 可用 `.optional()`, (中文(简体) ), `.nullable()`等在呼叫现场.

#### 歧视性结合与倒退

`discriminatedUnionWithFallback(discriminator, variants)` 使用与 `z.discriminatedUnion` 并返回一个响应计划 对于一个联盟,它的变体 设定随着时间的推移增长, 所以读容忍变体 这个消费者尚不知道.

它只用于答复。 要求宣布自己 `z.discriminatedUnion` 在同一个变体上,一个未知变体是一个客户端错误而不是可以容忍的东西.

|  | `z.discriminatedUnion` (请求) | `discriminatedUnionWithFallback` (答复) |
| --- | --- | --- |
| 未知歧视者 | 拒绝 | 崩溃后退 |
| 已知变体上未知的顶级密钥 | 脱去 | 脱去 |
| 缺少字段, 无效值 | 拒绝 | 拒绝 |

`z.union` 不能表达这一点。 它的倒置分枝匹配任何未知值, 所以一个已知的变体如果字段不好, 每个分枝都会失败, 并报告不透明 `invalid_union` 每个分支都有一个嵌入错误。 重写未知的歧义者首先意味着反应通常带有歧视性,并且只报告违法领域的问题,因此拒绝的反应可以从日志中诊断出来.

#### Enum 验证助手

这个软件包提供四个enum验证帮助,以覆盖不同的使用大小写:

**退后验证( 有连接) :**

-   `requiredEnumWithFallback(values)` - 无效的价值观被强迫 `ENUM_FALLBACK` (单位:千美元)`"UNRECOGNIZED_"`),一种商业文本中性的哨兵,自动附在enum类型上. `undefined` 无法验证 .
-   `optionalEnumWithFallback(values)` - 无效的价值观被强迫 `ENUM_FALLBACK` (单位:千美元)`"UNRECOGNIZED_"`) (中文(简体) ). `undefined` 通过时为 `undefined`。 。 。 .

**严格验证( 无倒计时 ) :**

-   `requiredEnum(values)` - 包装 `z.enum()` 需要严格验证。 无效的值失败验证 .
-   `optionalEnum(values)` - 包装 `z.enum()` 可选的严格验证。 无效的值失败验证, 但是 `undefined` 允许.

**缩小类型 :** 所有帮助者拒绝加宽 `string[]` 编译时的数组。 当通过一个预先宣布的变量时,使用 `as const` 以保留文字类型:

```ts
// Inline arrays work as-is
requiredEnum(["a", "b"]);

// Pre-declared variables require `as const`
const VALUES = ["a", "b"] as const;
requiredEnum(VALUES);

// Without `as const`, the type widens to string[] and is rejected
const widened = ["a", "b"];
requiredEnum(widened); // TS error
```

```ts
import {
  apiErrors,
  booleanString,
  commaSeparatedArray,
  dateTimeSchema,
  discriminatedUnionWithFallback,
  ENUM_FALLBACK,
  nonEmptyString,
  objectId,
  optionalEnum,
  optionalEnumWithFallback,
  requiredEnum,
  requiredEnumWithFallback,
  uuid,
} from "@clipboard-health/contract-core";
import { z, type ZodError } from "zod";

function logError(error: unknown) {
  console.error((error as ZodError).issues[0]!.message);
}

apiErrors.parse({
  errors: [
    {
      code: "NotFound",
      detail: "Resource 'b146a790-9ed1-499f-966d-6c4905dc667f' not found",
      id: "6191a8a0-96ff-4d4b-8e0f-746a5ab215f9",
      status: "404",
      title: "Not Found",
    },
  ],
});

// Comma-separated array examples
// Designed for shared contracts: server receives "CNA,RN" (string), client passes ["CNA", "RN"] (array).
// Both normalize to the same typed array output.
const workerTypes = commaSeparatedArray(requiredEnum(["CNA", "RN", "LVN"]));

// Server-side: comma-separated string from query params
const fromString = workerTypes.parse("CNA,RN");
// => ["CNA", "RN"]
console.log(fromString);

// Client-side: typed array
const fromArray = workerTypes.parse(["CNA", "LVN"]);
// => ["CNA", "LVN"]
console.log(fromArray);

// Composes with other schemas
const workerIds = commaSeparatedArray(objectId).optional();
const dates = commaSeparatedArray(dateTimeSchema());

// Works with .optional()
const noIds = workerIds.parse(undefined);
// => undefined
console.log(noIds);

const someDates = dates.parse("2026-01-01T00:00:00.000Z,2026-01-02T00:00:00.000Z");
// => [Date, Date]
console.log(someDates[0] instanceof Date); // true

booleanString.parse("true");

try {
  booleanString.parse("invalid");
} catch (error) {
  logError(error);
  // => Invalid enum value. Expected 'true' | 'false', received 'invalid'
}

nonEmptyString.parse("hello");
try {
  nonEmptyString.parse("");
} catch (error) {
  logError(error);
  // => String must contain at least 1 character(s)
}

// UUID validation examples
uuid.parse("b8d617bb-edef-4262-a6e3-6cc807fa1b26");
try {
  uuid.parse("invalid");
} catch (error) {
  logError(error);
  // => Invalid UUID format
}

// DateTime schema examples
// Accepts ISO-8601 datetime strings and Date objects, normalizes to Date.
// Composable with .optional(), .nullable(), etc.
const createdAt = dateTimeSchema().parse("2026-03-15T10:30:00.000Z");
// => Date object
console.log(createdAt instanceof Date); // true
console.log(createdAt.toISOString()); // "2026-03-15T10:30:00.000Z"

// Date objects pass through as-is
const fromDate = dateTimeSchema().parse(new Date("2026-03-15T10:30:00.000Z"));
// => Date object
console.log(fromDate instanceof Date); // true

try {
  dateTimeSchema().parse("2026-03-15"); // date-only string
} catch (error) {
  logError(error);
  // => Invalid datetime
}

try {
  dateTimeSchema().parse(1_773_340_050_000); // epoch number
} catch (error) {
  logError(error);
  // => Invalid union
}

// Optional usage — compose at the call site
const schema = dateTimeSchema().optional();
const noDate = schema.parse(undefined);
// => undefined
console.log(noDate);

const someDate = schema.parse("2026-03-15T10:30:00.000Z");
// => Date object
console.log(someDate);

// Enum with fallback examples
// ENUM_FALLBACK is a neutral sentinel ("UNRECOGNIZED_") automatically appended
// to the enum type. Consumers cannot choose their own fallback value, preventing
// misuse where a business-meaningful value is treated as a default.

/* -- required -- */
const requiredStatusEnumSchema = requiredEnumWithFallback(["pending", "completed", "failed"]);
// type RequiredStatusEnum = "pending" | "completed" | "failed" | "UNRECOGNIZED_"
type RequiredStatusEnum = z.infer<typeof requiredStatusEnumSchema>;

const completedStatus: RequiredStatusEnum = requiredStatusEnumSchema.parse("completed");
// => "completed"
console.log(completedStatus);

const additionalStatus = requiredStatusEnumSchema.parse("additional");
// => "UNRECOGNIZED_" (ENUM_FALLBACK)
console.log(additionalStatus);
console.log(additionalStatus === ENUM_FALLBACK); // true

try {
  requiredStatusEnumSchema.parse(undefined);
} catch (error) {
  logError(error);
  // => Validation error
}

/* -- optional -- */
const optionalStatusEnumSchema = optionalEnumWithFallback(["pending", "completed", "failed"]);
// type OptionalStatusEnum = "pending" | "completed" | "failed" | "UNRECOGNIZED_" | undefined
type OptionalStatusEnum = z.infer<typeof optionalStatusEnumSchema>;

const failedStatus: OptionalStatusEnum = optionalStatusEnumSchema.parse("failed");
// => "failed"
console.log(failedStatus);

const extraStatus = optionalStatusEnumSchema.parse("extra");
// => "UNRECOGNIZED_" (ENUM_FALLBACK)
console.log(extraStatus);

const undefinedStatus = optionalStatusEnumSchema.parse(undefined);
// => undefined
console.log(undefinedStatus);

// Strict enum examples (no fallback behavior)
// Use these when invalid values should fail validation rather than being coerced.
// Ideal for user types, authentication, and critical business logic.

/* -- required strict -- */
const requiredUserTypeSchema = requiredEnum(["admin", "worker", "workplace"]);
// type RequiredUserType = "admin" | "worker" | "workplace"
type RequiredUserType = z.infer<typeof requiredUserTypeSchema>;

const adminUser: RequiredUserType = requiredUserTypeSchema.parse("admin");
// => "admin"
console.log(adminUser);

try {
  requiredUserTypeSchema.parse("invalid");
} catch (error) {
  logError(error);
  // => Invalid enum value. Expected 'admin' | 'worker' | 'workplace', received 'invalid'
}

try {
  requiredUserTypeSchema.parse(undefined);
} catch (error) {
  logError(error);
  // => Required
}

/* -- optional strict -- */
const optionalUserTypeSchema = optionalEnum(["admin", "worker", "workplace"]);
// type OptionalUserType = "admin" | "worker" | "workplace" | undefined
type OptionalUserType = z.infer<typeof optionalUserTypeSchema>;

const workerUser: OptionalUserType = optionalUserTypeSchema.parse("worker");
// => "worker"
console.log(workerUser);

const noUserType = optionalUserTypeSchema.parse(undefined);
// => undefined
console.log(noUserType);

try {
  optionalUserTypeSchema.parse("invalid");
} catch (error) {
  logError(error);
  // => Invalid enum value. Expected 'admin' | 'worker' | 'workplace', received 'invalid'
}

// Discriminated union with fallback examples
// Takes the same arguments as z.discriminatedUnion and returns a response schema
// that tolerates variants this consumer does not know yet.
const notificationVariants = [
  z.object({
    channel: z.literal("EMAIL"),
    emailAddress: z.string().email(),
  }),
  z.object({
    channel: z.literal("SMS"),
    phoneNumber: nonEmptyString,
  }),
] as const;

const notificationResponseSchema = discriminatedUnionWithFallback("channel", notificationVariants);

const emailNotification = notificationResponseSchema.parse({
  channel: "EMAIL",
  emailAddress: "worker@example.com",
});
// => { channel: "EMAIL", emailAddress: "worker@example.com" }
console.log(emailNotification);

// A variant this consumer does not recognize yet collapses to ENUM_FALLBACK.
const unrecognizedNotification = notificationResponseSchema.parse({
  channel: "PUSH",
  deviceToken: "abc123",
});
// => { channel: "UNRECOGNIZED_" }
console.log(unrecognizedNotification);

// A known variant with a bad field still fails, naming the field.
try {
  notificationResponseSchema.parse({ channel: "EMAIL", emailAddress: 3 });
} catch (error) {
  logError(error);
  // => Expected string, received number
}

// Requests use z.discriminatedUnion directly: an unknown variant is a client
// error, not something to tolerate.
const notificationRequestSchema = z.discriminatedUnion("channel", [...notificationVariants]);

try {
  notificationRequestSchema.parse({ channel: "PUSH", deviceToken: "abc123" });
} catch (error) {
  logError(error);
  // => Invalid discriminator value. Expected 'EMAIL' | 'SMS'
}
```

## 地方发展指挥部

见 [`package.json`](https://npmcn.com/package/%40clipboard-health/contract-core/package.json) `scripts` 用于命令列表.

## 常见问题

### @clipboard-health/contract-core 是什么？

为剪贴板的合同共享Zod计划\.

### 如何安装 @clipboard-health/contract-core？

在项目目录运行 npm install @clipboard-health/contract-core，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：zod（^3）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @clipboard-health/contract-core 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @clipboard-health/contract-core 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @clipboard-health/contract-core 可以商用吗？

@clipboard-health/contract-core 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @clipboard-health/contract-core 的下载量有多少？

根据 npm 官方下载统计，@clipboard-health/contract-core 在 2026/10/10 – 2026/11/08 这 30 天内被下载 124,066 次，日均约 4,136 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @clipboard-health/contract-core 还在维护吗？

最新版本 4\.6\.15 发布于 2026/11/05（4 天前）；至今共发布 490 个版本，其中过去 12 个月发布了 391 个；首次发布于 2024/10/23。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

