@adobe/data

中文文档
0.10.32发布于 2026/11/05TypeScriptES Module近 30 天下载 10万

Adobe data oriented programming library

原始使用文档
文档目录17 节
  1. Documentation
  2. Breaking API Changes
  3. Data Oriented Programming
  4. Data
  5. Why immutable Data?
  6. What is Data Oriented Design?
  7. Data Schemas
  8. Normalized Data
  9. Observables
  10. Observable Types
  11. Observable Creation
  12. Observable Modification
  13. Cache
  14. BlobStore
  15. Schemas
  16. Entity Component System (ECS)
  17. What is an ECS?

@adobe/data

Adobe Data Oriented Programming Library

Documentation

API Reference

ECS Performance Test

Breaking API Changes

Until we reach 1.0.0, minor version changes may be API breaking.

Data Oriented Programming

This library is built using a data oriented and functional programming paradigm. We prefer composition over inheritance, avoid classes when possible and emphasize separation of concerns.

Data

This library uses data oriented design paradigm and prefers pure functional interfaces whenever practical.

For our purposes, Data is immutable, (de)serializable objects and primitives — JSON extended with ReadonlySet, ReadonlyMap, and Blob. A ReadonlyArray is ordered (position is meaningful); a ReadonlySet / ReadonlyMap is unordered. Serialize Set/Map-bearing Data with Data.stringify / Data.parse (plain JSON.stringify renders a Set/Map as {}); equals compares them faithfully.

Why immutable Data?

We prefer Data because it is easy to:

  • serialize
  • deserialize
  • inspect
  • compare
  • hash
  • validate

We prefer immutable Data because it is easy to:

  • reason about
  • avoid side effects
  • avoid defensive copying
  • use for pure function arguments and return values
  • use with concurrency
  • memoize results
    • use as cache key (stringified)
    • use as cache value

What is Data Oriented Design?

Sanders Mertens covers this thoroughly in his ECS FAQ:

https://github.com/SanderMertens/ecs-faq?tab=readme-ov-file#what-is-data-oriented-design

Data Schemas

When runtime type information is required we use JSON Schema. In order to avoid redundancy, we can use FromSchema to derive a typescript type at compile time.

Example:

const Float32Schema = { type: "number", precision: 1 } as const satisfies Schema;
const Float32 = FromSchema<typeof Float32Schema>; // number

It is important that we use as const for the schema definition. Without that, the typeof Float32Schema would be { type: string, precision: number } instead of { type: "number", precision: 1 } and we would not be able to derive a correct type using FromSchema.

Normalized Data

Data is considered "Normalized" when all object keys contained anywhere within it are lexigraphically sorted. We include a normalize function which performs this conversion. This is particularly useful when you want to use data as a cache key.

const notNormalized = { b: 2, a: 1 };
const normalized = normalize(notNormalized); // { a: 1, b: 2 }

normalize operates on plain JSON structure only — it does not canonicalize Set or Map values (which have no JSON form). Don't feed Set/Map-bearing Data through normalize for cache-keying; key on a Data.stringify of the value, or model the collection with plain arrays/objects where a canonical cache key is required.

Observables

An Observable<T> is a subscription function that you can pass a callback function to. Your callback function can accept a single argument of type T. The subscription function returns a dispose function that accepts no parameters and can be called at any point in the future to cancel your subscription.

Your callback function may be called back synchronously (before the initial call returns) zero or one times and asynchronously later any number of times.

For more information see the Observable API documentation

Observable Types

/**
 * Called to add a new observer to an Observable.
 * Returns an Unobserve function that can be called to stop observing the Observable.
 */
export type Observable<T> = (observer: Callback<T>) => Unobserve;
/**
 * Callback function called zero or more times with a sequence of values.
 * *may* be called back synchronously, immediately when selector function is called.
 * *may* also be called back asynchronously later any number of times.
 * *may* be called multiple sequential times with the same value.
 */
export type Callback<T> = (value: T) => void;
/**
 * Function called to stop observing an Observable.
 */
export type Unobserve = () => void;

An Observable can be thought of sort of like a Promise but with a few important differences.

  • A Promise only yields a single value, an Observable yields a sequence of values.
  • A Promise can reject with an error, an Observable can not. (It could yield type MyResult | MyError though.)
  • A Promise can only resolve asynchronously, an Observable may yield an initial result synchronously.
    • An Observable is allowed to call the Callback callback function immediately upon observation if it has a value.
  • A Promise begins executing immediately, an Observable may lazily wait for a first observer before taking any action.
  • An Observable can be unobserved.

Observable Creation

This simple definition of an Observable makes it very easy to create them from various sources.

  • fromConstant<T>(value: T) => Observable<T>
  • fromPromise<T>(promise: Promise<T>): Observable<T>
  • fromPromiseWithError<T, E extends Error>(promise: Promise<T>): Observable<T | E>
  • fromObservableProperties converts an object with named Observable values into a single Observable of an object with corresponding types.

For instance:

fromObservables({ a: fromConstant(1), b: fromConstant("s")})
// yields type Observable<{ a: number, b: string }>

fromObservableProperties will only yield a result once every contained observable has provided a result. If some properties are optional then use the withOptional higher order function described below.

Observable Modification

They are also very easy to modify in order to build higher order Observables.

For the purposes of discussion let us use an array to indicate the sequential values yielded by an Observable with the first element being any synchronous callback and void meaning no synchronous callback.

So our fromConstant(12) would yield [12] and fromPromise(Promise.resolve(12)) would yield [void, 12]

These examples will use the form of: Sequence Before => Higher Order Function => Sequence After.

withDeduplicate removes any sequentially equivalent values:

[1, 1, 2, 2, 2, 3] => withDeduplicate => [1, 2, 3]

withDefault replaces any undefined values, including initial synchronous value with a default value:

[void, 1, 2, undefined, 4] => withDefault(-1) => [-1, 1, 2, -1, 4]

withMap applies a mapping function to each value at notification time:

[void, 1, 2, 3] => withMap(x => x * 2) => [void, 2, 4, 6]

withOptional converts an Observable<T> to Observable<T | undefined> and will always respond synchronously.

[void, 1, 2, 3, 4] => withOptional => [undefined, 1, 2, 3, 4]

Cache

The cache module contains functions and interfaces related to caching, hashing, memoization and storage and retrieval of Blobs.

The memoize function and BlobStore are the most important public interfaces in the cache submodule. They are described below. See the API reference for hashing and other lower level functions.

The memoize function can be used to cache expensive, deterministic, asynchronous functions that take data arguments and return data results. In addition to caching the results, it also blocks multiple simultaneous calls with the same arguments and makes them wait for the first result.

BlobStore

It is important to handle Blobs correctly within an application.

The BlobStore interface and corresponding blobStore exported instance provide a convenient way to convert Blobs into small JSON handles to them called BlobRefs. Those BlobRefs can later be converted back into a Blob.

Blobs within the blobStore are generally persisted across sessions using the browsers buid in Cache storage.

BlobRefs have a number of advantages over directly using blobs. BlobRefs are:

  • small json objects
  • deterministic for each Blob based on mime type and content.
  • suitable for persistence to locations with limited size.
  • suitable for use as a cache key
  • suitable for use as a cache value

Schemas

Contains some standard data type schemas in JSON Schema format for convenience. These types are most frequently used when describing components within the Entity Component System. Knowing the precise size and signedness of primitive numeric types allows the ECS to store these values within tightly packed typed arrays internally. This makes memory usage and processing time more efficient.

Entity Component System (ECS)

A high-performance, strongly typed ECS database for TypeScript, inspired by Flecs. All application state is modeled as composable plugins, and all mutations flow through observable, undoable transactions.

For a complete guide covering plugins, transactions, observability, composition, and transient/ephemeral semantics, see the ECS README.

import { Database } from "@adobe/data/ecs";

const myPlugin = Database.Plugin.create({
  resources: {
    score: { default: 0 as number },
  },
  transactions: {
    addPoints: (t, points: number) => {
      t.resources.score += points;
    },
  },
});

const db = Database.create(myPlugin);
db.observe.resources.score((score) => console.log("Score:", score));
db.transactions.addPoints(10);

What is an ECS?

Sanders Mertens covers this thoroughly in his ECS FAQ:

https://github.com/SanderMertens/ecs-faq?tab=readme-ov-file#what-is-ecs

In addition to the standard Entity, Component, and System definitions, we also use the term Resource — a global singleton value defined on the ECS itself, not attached to any specific entity.

版本与发布记录

@adobe/data 共发布 190 个版本,首次发布于 2025/05/21;过去 12 个月发布了 134 个版本。

版本发布日期距今
0.10.32latest2026/11/051 天前
0.10.312026/11/033 天前
0.10.302026/10/2314 天前
0.10.292026/10/2314 天前
0.10.282026/10/1621 天前
0.10.272026/10/1126 天前

关于 @adobe/data 的常见问题

@adobe/data 是什么?

Adobe data oriented programming library

如何安装 @adobe/data?

在项目目录运行 npm install @adobe/data,或使用 pnpm add / yarn add / bun add。

@adobe/data 支持 TypeScript 吗?

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

@adobe/data 支持 ESM 还是 CommonJS?

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

@adobe/data 可以商用吗?

@adobe/data 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@adobe/data 的下载量有多少?

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

@adobe/data 还在维护吗?

最新版本 0.10.32 发布于 2026/11/05(1 天前);至今共发布 190 个版本,其中过去 12 个月发布了 134 个;首次发布于 2025/05/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。