@eturino/key-set

中文文档
6.0.0发布于 2026/08/31MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 8900

(简体中文) https://github.com/eturino/ruby key set (英语)) KeySet 有4个类来代表 All, None, Some, and AllExcuseSome 的概念,最后两个类有排序的 Uniq 密钥列表,全部有相交计算

中文使用文档
文档目录25 节
  1. V6 正在中断更改
  2. 打破 v5 中的变化
  3. 安装
  4. 使用量
  5. 创建 : all() , (中文(简体) ), none() , (中文(简体) ), some([...]) , (…
  6. .elements , (中文(简体) ), .elementsList 财务报告和审定财务报表 elementsSo…
  7. type
  8. representsXXX()
  9. clone()
  10. isEqual(other)
  11. invert()
  12. remove(other)
  13. intersect(other)
  14. union(other)
  15. includes(element)
  16. 序列化
  17. 分析
  18. 杰森·斯克马
  19. 类型预测
  20. UTI 函数
  21. UTI 数组类型
  22. ComposedKeySet
  23. 正在检查 a 上的元素 ComposedKeySet
  24. 其它 ComposedKeySet 方法
  25. 序列化 a ComposedKeySet

密钥集

npm version CI

Github 重播这里

键盘, 有 4 个 类, 代表 : All, (中文(简体) ), None, (中文(简体) ), Some,以及 AllExceptSome最后两个有内部 Set 键,所有键都有相交计算.

它还有一个概念: ComposedKeySet 包含可采取行动的 KeySets 列表,最后随 collapseUnion() 或者说 collapseIntersect()

(原件:TypeScript port of https://github.com/eturino/ruby key set (英语)(中文(简体) )

V6 正在中断更改

  • new ComposedKeySet([]) 现在将空列表正常化为单个 all()路边 composedKeySetFrom([]) 总是这样 之前建筑师保留了空列表, 其中 contains() 已回复 true (空虚地)而新的 containsByUnion() 会回答 false。 。 。 .
  • 已公布的切入点从 dist/ 改为 build/后,一个 exports 地图 : import 决定 build/module/index.js (ES模块)和 require 决定 build/main/index.js (共同JS),每个都有自己的 .d.ts。 。 。 . main, (中文(简体) ), module 财务报告和审定财务报表 types 仍为年长的捆绑者申报。 按名称导入包不受影响; 深度导入 a dist/... 路径不是 exports 现在只允许地图 @eturino/key-set/schemas/* 财务报告和审定财务报表 @eturino/key-set/package.json 作为子路径.
  • ES模块构建不再是一个单一的捆绑文件,它现在在本地节点无害环境管理下运作:相对的规格人员携带它们 .js 扩展和 build/module/package.json 标记目录为 type: module在v6之前 module 建筑只能由捆绑者解决.
  • KEY_SET_TYPES, (中文(简体) ), _IS_NODE_ENVIRONMENT 财务报告和审定财务报表 isKeyLabelBase 不再从模块中导出。 没有一个从货包入境点再出口 所以只有深度输入 src/ 可能已经到达他们.
  • allExceptSomeForced([]) 现在丢出一个消息名称错误 allExceptSomeForced。它曾经说 someForced。 。 。 .

V6中也是新的: ComposedKeySet.containsByUnion() 编号 : containsByIntersection(),并发表 杰森·斯克马 用于序列格式.

固定在v6中: module 建筑(dist/index.mjs 在5.x)中投掷 Dynamic require of "node:util" is not supported 当它在类似节点的运行时间 -- -- 无害环境管理输出服务器捆绑 -- -- 中被评价为真正的无害环境管理时,或者通过路径导入该文件。 它没有影响 require(), (中文(简体) ), import 按软件包名称( 5. x 没有) exports 映射, 因此节点解析 main),或浏览器捆绑,其中 process 未定义和 node:util 树枝从未被取走.

打破 v5 中的变化

从五年级起 KeySet 元素编码为被冻结 Set 而不是数组。 它暴露为 keySet.elements。 。 。 . 这个 keySet.keys 别名已被删除.

作为数组用途的元素列表 keySet.elementsList,用于排序版本 keySet.elementsSorted。 。 。 .

你可以多吃点 读取内容部分中的信息。 。 。 .

安装

pnpm add @eturino/key-set, (中文(简体) ), yarn add @eturino/key-set 或者说 npm install @eturino/key-set。 。 。 .

使用量

我们有四个班:

  • KeySetAll: 代表可能键的全部(𝕌(中文(简体) )
  • KeySetNone: 代表一个空集(∅(中文(简体) )
  • KeySetSome: 代表一组混凝土(A ⊂ 𝕌(中文(简体) )
  • KeySetAllExceptSome: 代表一个集合的补充,除给定元素外的所有元素(A' = {x ∈ 𝕌 | x ∉ A}(中文(简体) ) (见 维基百科中的补充(中文(简体) )

我们可以有一个键盘:

  • string编号
  • number编号
  • 对象为 key (单位:千美元)string 或者说 number和 label (单位:千美元)string(中文(简体) )

所有元素都必须是同一类的.

创建 : all(), (中文(简体) ), none(), (中文(简体) ), some([...]), (中文(简体) ), allExceptSome([...]), (中文(简体) ), allKeySet(), (中文(简体) ), noneKeySet(), (中文(简体) ), someKeySet([...]), (中文(简体) ), allExceptSomeKeySet([...]), (中文(简体) ), someForced([...]), (中文(简体) ), allExceptSomeForced([...])

使用构建函数构建您的 keySets

import { all, allKeySet, none, noneKeySet, some, someKeySet, allExceptSome, allExceptSomeKeySet, someForced, allExceptSomeForced } from "@eturino/key-set";

all(); // => returns a new instance of KeySetAll
allKeySet(); // => returns a new instance of KeySetAll
none(); // => returns a new instance of KeySetNone
noneKeySet(); // => returns a new instance of KeySetNone

some([1, 3, 2, 3]); // returns a new instance of KeySetSome with keys Set<1, 3, 2>
someKeySet([1, 3, 2, 3]); // returns a new instance of KeySetSome with keys Set<1, 3, 2>
some([]); // returns a new instance of KeySetNone
someKeySet([]); // returns a new instance of KeySetNone

allExceptSome([1, 3, 2, 3]); // returns a new instance of KeySetAllExceptSome with keys Set<1, 3, 2>
allExceptSomeKeySet([1, 3, 2, 3]); // returns a new instance of KeySetAllExceptSome with keys Set<1, 3, 2>
allExceptSome([]); // returns a new instance of KeySetAll
allExceptSomeKeySet([]); // returns a new instance of KeySetAll

someForced([1, 3, 2, 3]); // returns a new instance of KeySetSome with keys Set<1, 3, 2>
someForced([]); // throws an InvalidEmptySetError

allExceptSomeForced([1, 3, 2, 3]); // returns a new instance of KeySetAllExceptSome with keys Set<1, 3, 2>
allExceptSomeForced([]); // throws an InvalidEmptySetError

.elements, (中文(简体) ), .elementsList 财务报告和审定财务报表 elementsSorted

  • .elements 返回内部 Set 用钥匙。 KeySet 从未变异过它,它通过 Object.freeze()但请注意,冻结 Set 不停止 .add()编号 :.delete() - 按惯例视其为只读,并使用 .elementsList 如果您需要一个可以拥有的阵列.
  • .elementsList 返回带有内部集元素的新数组.
  • .elementsSorted 返回带有内部集元素的新阵列,排序.
some([1, 3, 2, 3]).elements; // => Set<1, 3, 2>
some([1, 3, 2, 3]).elementsList; // => [1, 3, 2]
some([1, 3, 2, 3]).elementsSorted; // => [1, 2, 3]

allExceptSome([1, 3, 2, 3]).elements; // => Set<1, 3, 2>
allExceptSome([1, 3, 2, 3]).elementsList; // => [1, 3, 2]
allExceptSome([1, 3, 2, 3]).elementsSorted; // => [1, 2, 3]

type

所有密钥集显示一个 type 返回成员的财产 KeySetTypes um.

  • KeySetAll 返回时 ALL
  • KeySetAllExceptSome 返回时 ALL_EXCEPT_SOME
  • KeySetNone 返回时 NONE
  • KeySetSome 返回时 SOME

这些类型也作为字符串 TypeScript 类型的结合而被曝光 KeySetTypesEnumValues。 。 。 .

type 在v1.x对v2.x中

v2.0 更改返回的值 type,使它们尖叫 SNAKE CASE,这样可以更容易地与GraphQL enums集成.

在v1.x中,数值是 all, (中文(简体) ), allExceptSome, (中文(简体) ), none 财务报告和审定财务报表 some。 。 。 .

representsXXX()

所有 KeySet 显示 4 个方法 representXXX()。每个班都假冒返回,除了自己的.

  • representsAll()数字 : KeySetAll 返回时 true
  • representsNone()数字 : KeySetNone 返回时 true
  • representsSome()数字 : KeySetSome 返回时 true
  • representsAllExceptSome()数字 : KeySetAllExceptSome 返回时 true

clone()

所有键盘有一个 clone() 方法,它将返回代表同一密钥Set的同类新实例.

如果键盘是 KeySetSome 或者说 KeySetAllExceptSome,它们将有一个带有相同密钥的阵列.

const newKeySet = keySet.clone();

isEqual(other)

所有键盘都有 isEqual(other) 如果返回真实的方法 other keySet属于同一类,代表同一类的KeySet.

如果键盘是 KeySetSome 或者说 KeySetAllExceptSome,它们必须有一个有相同密钥的阵列.

invert()

所有键盘都有 invert() 方法返回相反类的实例,代表互补的 KeySet. (见 维基百科中的补充(中文(简体) )

  • KeySetAll ⟷ KeySetNone
  • KeySetSome ⟷ KeySetAllExceptSome
const complementaryKeySet = keySet.invert();

remove(other)

返回新的键盘, 其区别在于此Set - 其他Set (A - B)

const diffKeySet = keySet.remove(other);

intersect(other)

返回两个集相交的新密钥组 (A ∩ B),代表两组中的要素

const diffKeySet = keySet.intersect(other);

union(other)

返回两个集结合的新密钥组 (A U B),代表 A 或 B 中的元素

const unionKeySet = keySet.union(other);

includes(element)

别名 contains(element)。 。 。 .

如果 KeySet 包含给定元素, 返回布尔定义 .

const element = "A";

const ksAll: KeySetAll<string> = all<string>();
ksAll.includes(element); // => true
ksAll.contains(element); // => true

const ksNone: KeySetNone<string> = none<string>();
ksNone.includes(element); // => false
ksNone.contains(element); // => false

const ksSome: KeySetSome<string> = some(["A", "B", "C"]);
ksSome.includes(element); // => true
ksSome.contains(element); // => true

const ksSome2: KeySetSome<string> = some(["X", "Y", "Z"]);
ksSome2.includes(element); // => false
ksSome2.contains(element); // => false

const ksAllExceptSome: KeySetAllExceptSome<string> = allExceptSome(["A", "B", "C"]);
ksAllExceptSome.includes(element); // => false
ksAllExceptSome.contains(element); // => false

const ksAllExceptSome2: KeySetAllExceptSome<string> = allExceptSome(["X", "Y", "Z"]);
ksAllExceptSome2.includes(element); // => true
ksAllExceptSome2.contains(element); // => true

序列化

KeySet 的序列化代表KeySetSerialized)是一个普通对象,与 type 选择 elements。 。 。 .

  • { type: "ALL" }
  • { type: "NONE" }
  • { type: "SOME", elements: [1, 2, 3] }
  • { type: "ALL_EXCEPT_SOME", elements: [1, 2, 3] }

键盘的序列化表达有两种方式

  • keySet.serialized()
  • serializeKeySet(keySet)

对于KeyLabel集和组成集,有专用功能,类型更窄:

  • serializeKeyLabelSet(keyLabelSet)
  • serializeComposedKeySet(comp)
  • serializeComposedKeyLabelSet(comp)

分析

我们可以从序列化的表示中创建一个 KeySet

  • parseKeySet(serialized)
  • parseKeyLabelSet(serialized)
  • parseComposedKeySet(serialized)
  • parseComposedKeyLabelSet(serialized)

也可以将实际的键盘传递到 parseKeySet,它将返回给定的键盘而不触碰它.

无效的串行值抛出 InvalidKeySetError。 。 。 .

杰森·斯克马

串行电线格式以JSON Schema(2020-12草案)发布,这样其他语言的客户端就可以在不依赖此库的情况下验证.

同样的两个简介 v1 格式, 不变 $defs 名字,相互切换需要一个 $id数字 :

文件描述用它来
key-set.schema.json什麽 parseKeySet() 接受验证此库的另一个客户端所写的有效载荷
key-set.canonical.schema.json什麽 serialized() 发射验证嵌入密钥集的手动编辑文件

两者都在 npm 包内运出 schemas/v1/,并用 URL 粘贴在不可更改性标签上:

https://raw.githubusercontent.com/eturino/ts-key-set/v6.0.0/schemas/v1/key-set.schema.json
https://raw.githubusercontent.com/eturino/ts-key-set/v6.0.0/schemas/v1/key-set.canonical.schema.json

在读取Postel定律时 选一个放任性 人类输入文件时选一个 犬科简介禁止 elements 打开 ALL编号 :NONE (允许者容忍一空阵列),禁止未知属性,并要求 uniqueItems。3个都不是这个库发出的形状,所以在手动编辑的文件上,每个文件都是一个值一个错误的字典,而不是一个静悄悄地不意味着它是什么样子的值.

Root schema 描述了单个序列化的 KeySet. 其他形状可处理为 $defs数字 :

指针形状
#/$defs/keySetKeySetSerialized (根),任意 Key 元素
#/$defs/keyLabelSetKeyLabelSetSerialized, (中文(简体) ), IKeyLabel 只包含元素
#/$defs/stringKeySet仅字符串元素( 仅定义配置)
#/$defs/composedKeySetComposedKeySetSerialized
#/$defs/composedKeyLabelSetComposedKeyLabelSetSerialized
#/$defs/composedStringKeySet组成, 只包含字符串元素( 仅包含名称配置)
#/$defs/key单人 Key
#/$defs/keyLabel单人 IKeyLabel
#/$defs/keySetType页:1 type 歧视者

如果您的文件格式密钥在普通字符串 ID 上,则指向 key-set.canonical.schema.json#/$defs/stringKeySet: 相同的犬科规则,与 elements 限于字符串, 所以一个数字或一个 IKeyLabel 是一个错误,而不是你从未打算接受的那种有效的密钥集.

这个 v1 路径中的版本 有线格式,而不是包,它涵盖两个配置:两个 $ids,一种格式. 它只有在序列化形状改变现有文档失败的方式时才会改变. 两种方案都与库在每次测试中的实际产出.

更进一步缩小范围 一个图案 一个已知的识别码 allOf 您想要自己的简介 items。收缩的唯一收缩; 犬科分支保持自己的 additionalProperties: false数字 :

{
  "allOf": [
    { "$ref": "https://raw.githubusercontent.com/eturino/ts-key-set/v6.0.0/schemas/v1/key-set.canonical.schema.json" },
    { "properties": { "elements": { "items": { "$ref": "#/$defs/myItemKey" } } } }
  ]
}

两种方法都无法表达: 排序 发射,和 IKeyLabel 元素被复制 按键,因此两个条目共享 a key 标签不相同者也不被排放 - uniqueItems 不抓住那对.

两个方案都比运行时分析器更严格:它们验证每个元素都是有效的 Key,哪个 parseKeySet 不检查,他们拒绝一个不集合的变态 elements (单位:千美元)null, (中文(简体) ), 0, (中文(简体) ), "", (中文(简体) ), false继续 ALL编号 :NONE,解析器读作缺席 elements。未知的属性被解析器和允许配置文件所允许; Cononical 配置文件拒绝这些属性,除非 IKeyLabel图书馆会发出它交给的东西.

类型预测

有类型的上游被曝光,一个是每个键盘类型,另一个是每个键盘序列化.

  • isKeySet(x): x is KeySet
  • isKeySetAll(x): x is KeySetAll
  • isKeySetAllExceptSome(x): x is KeySetAllExceptSome
  • isKeySetNone(x): x is KeySetNone
  • isKeySetSome(x): x is KeySetSome
  • isKeySetSerialized(x): x is KeySetSerialized
  • isKeySetAllSerialized(x): x is KeySetAllSerialized
  • isKeySetAllExceptSomeSerialized(x): x is KeySetAllExceptSomeSerialized
  • isKeySetNoneSerialized(x): x is KeySetNoneSerialized
  • isKeySetSomeSerialized(x): x is KeySetSomeSerialized

我们还有基于元素类型的类型上游,用于序列化和KeySet.

  • isKeySetOfNumbers
  • isKeySetOfStrings
  • isKeySetOfNumberKeyLabels
  • isKeySetOfStringKeyLabels
  • isKeySetSerializedOfNumbers
  • isKeySetSerializedOfStrings
  • isKeySetSerializedOfNumberKeyLabels
  • isKeySetSerializedOfStringKeyLabels

UTI 函数

Lib 还导出代码中使用的 2 个函数

  • setByKeys(listOrSet): 返回包含源列表独特元素的新集。 如果给定的元素是 KeyLabel, 则按密钥进行对比 .
  • sortKeys(iterableOfKeys): 排序密钥列表。 如果密钥实际上是 KeyLabel 对象,则按密钥排序. 否则,它们自然被分类。 返回带有排序键的新数组.

UTI 数组类型

Lib 也导出 2 个 util 阵列类型 EmptyArray<T> 财务报告和审定财务报表 NonEmptyArray<T>,带有相应的类型上游 isEmptyArray(),以及 isNonEmptyArray()。 。 。 .

const lists: Array<NonEmptyArray<any>> = [
  [1], // ok
  [], // error
];

const lists2: Array<EmptyArray<any>> = [
  [], // ok
  [1], // error
];

const a: string[] = [];
isEmptyArray(a); // => true (also sets that a is EmptyArray<string>)
isNonEmptyArray(a); // => false

const b: string[] = ["something"];
isEmptyArray(b); // => false
isNonEmptyArray(b); // => true (also sets that a is NonEmptyArray<string>)

ComposedKeySet

KeySets 列表的组成 .

在正常使用的情况下,不需要这样做,可以用 first.intersect(second) 或者说 first.union(second)。 。 。 .

但是,在另一些情况下,我们必须明确我们相互交织的两组问题.

譬如说. 我们有一份带有标签的项目清单,其中一个项目可以有多个标签. 我们需要用A、B和C等标签过滤那些没有D等标签的物品.

我们不能用 some(A, B, C).intersect(allExceptSome(D)) 因为那样就只能 some(A, B, C)。 。 。 . 所以我们用 composedKeySetFrom([some(A, B, C), allExceptSome(D)])。 。 。 .

这样,如果我们有一个搜索引擎 翻译这样的密钥集:

  • All => WHERE 1=1
  • None => WHERE 1=0
  • Some => WHERE list.contains(elements)
  • AllExceptSome => WHERE not list.contains(elements)

然后,上面的密钥将最终 WHERE items.labels.contains(A, B, or C) AND NOT items.labels.contains(D)

对于这个案子,我们得到了 ComposedKeySet

const comp = composedKeySetFrom([some(A, B, C), allExceptSome(D)]);

正在检查 a 上的元素 ComposedKeySet

两个语义,四个方法名:

  • containsByIntersection(element): 只有在 每个 列表中的密钥集包含它. contains(element) 及其别名 includes(element) 是同一个支票.
  • containsByUnion(element): 如果 任意 列表中的密钥集包含它.
const comp = composedKeySetFrom([some([1, 2, 3]), some([1, 4])]);

comp.containsByIntersection(1); // => true  (in both)
comp.containsByIntersection(3); // => false (only in the first)
comp.contains(3); // => false (alias of containsByIntersection)

comp.containsByUnion(3); // => true  (in the first)
comp.containsByUnion(5); // => false (in neither)

其它 ComposedKeySet 方法

  • collapseUnion() 编号 : collapseIntersect(): 将列表简化为单个键盘.
  • add(keySet) 编号 : addList(keySets): 新增了组合的 KeySet, 并添加了指定的组合 .
  • without(keySet) 编号 : withoutList(keySets): 一个新的编译KeySet,没有给定的集(与 isEqual) (中文(简体) ).
  • filter(predicate) 编号 : map(fn):来自幸存成员/被映射成员的新编成的KeySet.
  • compactUnion() 编号 : compactIntersect(): 将同类型成员合并成一个,通过联合或交叉.
  • invert(), (中文(简体) ), clone(), (中文(简体) ), isEqual(other), (中文(简体) ), toString(),以及 representsAll() 编号 : representsNone() 编号 : representsSome() 编号 : representsAllExceptSome()。 。 。 .
  • list: KeySets 的基础阵列。 将空列表正常化为单个 all()。 。 。 .

序列化 a ComposedKeySet

序列化为序列化KeySets的内部列表(阵列).

  • comp.serialized() 或者说 serializeComposedKeySet(comp),以及 serializeComposedKeyLabelSet(comp) 用于键盘集.
  • parseComposedKeySet(serialized),以及 parseComposedKeyLabelSet(serialized) 用于键盘集.

我们还有检查类型的职能:

  • isComposedKeySet(x): x is ComposedKeySet
  • isComposedKeyLabelSet(x): x is ComposedKeyLabelSet
  • isComposedKeySetSerialized(x): x is ComposedKeySetSerialized
  • isComposedKeyLabelSetSerialized(x): x is ComposedKeyLabelSetSerialized
  • isComposedKeySetSerializedRepresentsAll(x): x is ComposedKeySetAllSerialized
  • isComposedKeySetSerializedRepresentsNone(x): x is ComposedKeySetNoneSerialized
  • isComposedKeySetSerializedRepresentsSome(x): x is ComposedKeySetSomeSerialized
  • isComposedKeySetSerializedRepresentsAllExceptSome(x): x is ComposedKeySetAllExceptSomeSerialized

扬开版本

两者都是npm未公布的,无法安装. npm view 请不要列出它们,所以记录在这里.

  • 5.8.0 运出已编译的产出 5.7.0替换为 5.8.1。 。 。 .
  • 5.11.0 主软件包导出时缺少一些函数 。 已经取代了 5.11.1。 。 。 .

版本与发布记录

@eturino/key-set 共发布 49 个版本,首次发布于 2019/09/07;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
6.0.0latest2026/08/312 个月前
6.0.0-beta.0beta2026/08/312 个月前
5.11.12025/02/051.8 年前
5.11.02025/02/051.8 年前
5.10.02025/01/091.8 年前
5.9.12025/01/081.8 年前

关于 @eturino/key-set 的常见问题

@eturino/key-set 是什么?

(简体中文) https://github.com/eturino/ruby key set (英语)) KeySet 有4个类来代表 All, None, Some, and AllExcuseSome 的概念,最后两个类有排序的 Uniq 密钥列表,全部有相交计算

如何安装 @eturino/key-set?

在项目目录运行 npm install @eturino/key-set,或使用 pnpm add / yarn add / bun add。

@eturino/key-set 支持 TypeScript 吗?

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

@eturino/key-set 支持 ESM 还是 CommonJS?

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

@eturino/key-set 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@eturino/key-set 可以商用吗?

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

@eturino/key-set 的下载量有多少?

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

@eturino/key-set 还在维护吗?

最新版本 6.0.0 发布于 2026/08/31(2 个月前);至今共发布 49 个版本,其中过去 12 个月发布了 2 个;首次发布于 2019/09/07。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。