# @endo/patterns 中文文档

规范地址：https://npmcn.com/package/%40endo/patterns/

版本：2\.1\.0
npm 元数据更新时间：2026-08-13T22:54:43.976Z
中文译文更新时间：2026-11-13T16:53:06.653Z
软件包许可：Apache-2\.0

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

原始 npm 页面：https://www.npmjs.com/package/%40endo/patterns
原文对照：https://npmcn.com/package/%40endo/patterns/?lang=original
项目主页：https://github.com/endojs/endo/blob/master/packages/patterns/README.md
源码仓库：https://github.com/endojs/endo

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

- 包体积（解压后）：352 kB，46 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：6 个
- 首次发布：2023-03-07T20:45:29.514Z
- 最新版本发布：2026-08-13T22:54:43.844Z
- 近 30 天下载量：34837（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：30（近 12 个月 4 个）

## 中文简介

通过对象的匹配模式,以通过数据表示

## 安装

```sh
npm install @endo/patterns
```

也可以使用：`pnpm add @endo/patterns`、`yarn add @endo/patterns`、`bun add @endo/patterns`

## README

# `@endo/patterns`

可通过数据的匹配和验证模式,包括复制收集以及 界面保护.

## 概览

这个 **@ endo/ patters( 签名)** 软件包提供 `M` 创建模式的命名空间 匹配者可以验证可通过的数据,并描述行为合同. 这是上面的验证层 [@ endo/ pass 风格](https://npmcn.com/package/%40endo/pass-style/README.md), (中文(简体) ), 允许您在使用前检查与预期形状相匹配的数据.

模式使:

-   **数据验证**: 检查符合预期类型和结构的值
-   **接口合同**: 描述带有界面守护符的方法签名
-   **复制收藏**: CopySet, CopyBag, CopyMap 可通过的数据结构
-   **关键比较**: 分布式平等,用于比较不同瓦特的数值

## 快速启动

```javascript
import { M, mustMatch } from '@endo/patterns';

const specimen = harden({ foo: 3, bar: 4 });

const pattern = M.splitRecord(
  { foo: M.number() },                        // required properties
  { bar: M.string(), baz: M.number() }       // optional properties
);

mustMatch(specimen, pattern);
// throws: 'bar?: number 4 - Must be a string'
```

_为了最佳渲染效果,请使用 [Endo 参考文件](https://endojs.github.io/endo) 网站._

## M 命名空间

这个 `M` 对象提供了创建图案匹配器的方法 几类:

### 初级火柴

匹配特定的 JavaScript 类型 :

```javascript
M.any()           // Matches any passable
M.undefined()     // Matches undefined
M.null()          // Matches null
M.boolean()       // Matches true or false
M.number()        // Matches any number (including NaN, Infinity)
M.bigint()        // Matches any bigint
M.string()        // Matches any string
M.symbol()        // Matches registered/well-known symbols

// Constrained primitives
M.nat()           // Non-negative bigint
M.gte(5)          // Number >= 5
M.lte(100)        // Number <= 100
```

### 集装箱火柴

匹配复制本、复制记录和其他结构 :

```javascript
M.array()         // Any CopyArray
M.record()        // Any CopyRecord
M.set()           // Any CopySet
M.bag()           // Any CopyBag
M.map()           // Any CopyMap

// With constraints
M.array({ maxSize: 10 })          // Array with at most 10 elements
M.string({ maxSize: 100 })        // String with at most 100 characters

// Structured content
M.arrayOf(M.number())             // Array of numbers only
M.recordOf(M.string(), M.number()) // Record with string keys, number values
M.setOf(M.string())               // Set of strings only
```

### 结构匹配器

匹配特定形状 :

```javascript
// Split patterns: required, optional, rest
M.splitArray(
  [M.string(), M.number()],      // required elements
  [M.boolean()],                  // optional elements
  M.any()                         // rest elements
)

M.splitRecord(
  { name: M.string() },           // required properties
  { age: M.number() },            // optional properties
  M.any()                         // rest properties
)

// Partial matches
M.partial({ name: M.string() })  // Has at least 'name' property

// Split auto-detects array vs record
M.split({ x: M.number() }, M.any())
```

### 逻辑运算符

组合匹配者 :

```javascript
M.and(M.number(), M.gte(0), M.lte(100))   // 0 <= n <= 100
M.or(M.string(), M.number())               // String or number
M.not(M.undefined())                       // Anything except undefined
M.opt(M.string())                          // undefined or string (optional)
```

### 比较匹配符

匹配比对密钥的值 :

```javascript
M.eq('hello')     // Equal to 'hello'
M.neq(0)          // Not equal to 0
M.lt(10)          // Less than 10
M.lte(100)        // Less than or equal to 100
M.gte(0)          // Greater than or equal to 0
M.gt(-1)          // Greater than -1
```

### 特殊火柴

```javascript
M.remotable()           // Any remotable object
M.remotable('Counter')  // Remotable with specific label
M.error()               // Any error
M.promise()             // Any promise
M.eref(M.number())      // Number or promise for number (eventual reference)
M.kind('copyArray')     // Specific pass style
M.pattern()             // Any valid pattern
M.key()                 // Any valid Key
M.scalar()              // Any primitive or remotable
```

## 模式匹配

### 匹配( specimen,图案)

回返 `true` 如果标本符合模式, `false` 否则:

```javascript
import { M, matches } from '@endo/patterns';

matches(42, M.number());                    // true
matches('hello', M.number());               // false
matches([1, 2, 3], M.arrayOf(M.number())); // true
```

### mustMatch( specimen, 模式, 标签 )

如果标本不匹配, 则带有描述错误 :

```javascript
import { mustMatch } from '@endo/patterns';

mustMatch(42, M.string());
// throws: "number 42 - Must be a string"

mustMatch(-5, M.and(M.number(), M.gte(0)), 'count');
// throws: "count: number -5 - Must be >= 0"
```

错误消息旨在帮助您准确理解错误 与数据.

## 复制收藏

模式引入了基于三种可通行的收藏类型 `makeTagged()`数字 :

### 复制集

一组独有的密钥(原始或可再移动的密钥):

```javascript
import { makeCopySet } from '@endo/patterns';

const colors = makeCopySet(['red', 'blue', 'green']);

// Elements are sorted in rank order
// Duplicates are removed
// Can be passed between vats

// Pattern for sets
const ColorSet = M.setOf(M.string());
mustMatch(colors, ColorSet);  // passes
```

**为什么不使用 JavaScript 集 ?** Java 脚本 设定不能通过. CopySet被冻结,通过 `keyEQ`,可以高效地序列化.

### 复制文件夹

多集( 有计数要素) :

```javascript
import { makeCopyBag } from '@endo/patterns';

const inventory = makeCopyBag([
  ['apples', 5n],
  ['oranges', 3n],
  ['apples', 2n]   // counts are combined
]);

// Result: [['apples', 7n], ['oranges', 3n]]

const InventoryPattern = M.bagOf(M.string(), M.bigint());
mustMatch(inventory, InventoryPattern);
```

### 复制地图

从密钥到通过值的映射 :

```javascript
import { makeCopyMap } from '@endo/patterns';

const balances = makeCopyMap([
  ['alice', 100],
  ['bob', 50]
]);

// Keys are sorted in rank order
// Can use any Key as a key (not just strings!)

const remotableKey = Far('Key', {});
const map = makeCopyMap([[remotableKey, 'value']]);

const BalancesPattern = M.mapOf(M.string(), M.number());
mustMatch(balances, BalancesPattern);
```

**为什么不使用普通物体?** 复制映射支持 :

-   任意密钥作为密钥( 对象, 可调动, 不仅仅是字符串)
-   使用有效的密钥比较 `compareKeys()`
-   用于部分排序的子集关系

## 界面守护

界面保护描述对象的行为契约, 尤其有用 与 [@ endo/ exo (帮助)](https://npmcn.com/package/%40endo/exo/README.md)数字 :

### 创建界面保护

```javascript
import { M } from '@endo/patterns';

const CounterI = M.interface('Counter', {
  // Synchronous method
  increment: M.call(M.number()).returns(M.number()),

  // Method with optional arguments
  reset: M.call().optional(M.number()).returns(),

  // Method with rest arguments
  add: M.call(M.number()).rest(M.number()).returns(M.number()),

  // Async method (awaits arguments)
  asyncOp: M.callWhen(M.string()).returns(M.string())
});
```

### 方法守护结构

```javascript
// Basic call: call(required args...)
M.call(M.string(), M.number())

// With optional args
M.call(M.string()).optional(M.number())

// With rest args
M.call(M.string()).rest(M.any())

// Specify return type
M.call(M.string()).returns(M.number())

// Async method (awaits promise args)
M.callWhen(M.remotable()).returns(M.string())
```

### 与 Exo 合并

界面保护由 exos 自动执行 :

```javascript
import { makeExo } from '@endo/exo';
import { M } from '@endo/patterns';

const CounterI = M.interface('Counter', {
  increment: M.call(M.number()).returns(M.number())
});

const counter = makeExo('Counter', CounterI, {
  increment(n) {
    // n is guaranteed to be a number by the guard
    return count += n;
  }
});

counter.increment(5);      // OK
counter.increment('5');    // throws: Must be a number
```

这是远藤防御性编程的基础:卫兵验证输入 自动,因此您的方法可以专注于商业逻辑.

## 密钥比较

平等与秩序的密钥可以比较:

### 键EQ( 键 1, 键2)

使用分布式平等语义测试两个密钥是否相等 :

```javascript
import { keyEQ } from '@endo/patterns';

keyEQ('hello', 'hello');        // true
keyEQ(42, 42);                  // true
keyEQ([1, 2], [1, 2]);          // true (compares content)

const r1 = Far('Obj', {});
const r2 = Far('Obj', {});
keyEQ(r1, r1);                  // true (same remotable)
keyEQ(r1, r2);                  // false (different remotables)
```

### 比较 Keys( key1, key2)

返回比较结果 **部分顺序**数字 :

-   `0`: 键相等
-   `-1`: 键 1 < 键 2
-   `1`: 键 1 > 键 2
-   `NaN`: 密钥不可比

```javascript
import { compareKeys, keyLT, keyGT } from '@endo/patterns';

compareKeys('a', 'b');          // -1
compareKeys(5, 5);              // 0
compareKeys(10, 3);             // 1

// Convenience functions
keyLT('a', 'b');                // true
keyGT(10, 3);                   // true

// Incomparable keys
const r1 = Far('A', {});
const r2 = Far('B', {});
compareKeys(r1, r2);            // NaN (different remotables)
```

**为什么是局部命令?** 并不是所有的键都可以比较. 例如,不同的可移动性没有定义的顺序, CopySets 使用 子集关系.

## 密钥、图案和可通行等级

了解类型等级 :

```
Passable (everything that can pass)
├── Error
├── Promise
├── Key (stable, comparable)
│   ├── Primitives (null, undefined, boolean, number, bigint, string, symbol)
│   ├── Remotable
│   ├── CopyArray<Key>
│   ├── CopyRecord<Key>
│   ├── CopySet<Key>
│   ├── CopyBag<Key>
│   └── CopyMap<Key, Passable>
└── Pattern (describes a set of Passables)
    ├── Key (matches itself)
    └── Key-like with Matcher leaves
```

-   **可通行**: 能够跨越瓦特边界(来自 @endo/pass-tyle)
-   **密钥**: 可通行性中稳定和可比较的子集
-   **图案**: 描述匹配的可通性子集

## 与 Endo 软件包集成

-   **基金会**数字 : [@ endo/ pass 风格](https://npmcn.com/package/%40endo/pass-style/README.md) - 会是什么 已通过(密码)
-   **执行**数字 : [@ endo/ exo (帮助)](https://npmcn.com/package/%40endo/exo/README.md) - 使用界面保护 自动验证
-   **通讯**数字 : [@ endo/ eventual- send (日语)](https://npmcn.com/package/%40endo/eventual-send/README.md) - 发送 给已验证对象的信件

**完成教学**: 见 [消息传递](https://npmcn.com/package/docs/message-passing.md) 页:1 综合指南,说明模式如何与通行证式、exo和 最终发送.

## 深潜

详细执行情况:

-   [元帅对模式抽象级](https://npmcn.com/package/%40endo/patterns/docs/marshal-vs-patterns-level.md) - 类型vs passStyleof 对类型of
-   [类型定义](https://npmcn.com/package/%40endo/patterns/src/types.ts) - 完整的类型Script类型定义

## 常见问题

### @endo/patterns 是什么？

通过对象的匹配模式,以通过数据表示

### 如何安装 @endo/patterns？

在项目目录运行 npm install @endo/patterns，或使用 pnpm add / yarn add / bun add。

### @endo/patterns 支持 TypeScript 吗？

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

### @endo/patterns 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @endo/patterns 可以商用吗？

@endo/patterns 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @endo/patterns 的下载量有多少？

根据 npm 官方下载统计，@endo/patterns 在 2026/10/14 – 2026/11/12 这 30 天内被下载 34,837 次，日均约 1,161 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @endo/patterns 还在维护吗？

最新版本 2\.1\.0 发布于 2026/08/14（2 个月前）；至今共发布 30 个版本，其中过去 12 个月发布了 4 个；首次发布于 2023/03/08。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

