Skip to main content

SchemaFactory Class

Creates various types of schema for TreeNodes.

Signature

/** @sealed */
export declare class SchemaFactory<out TScope extends string | undefined = string | undefined, TName extends number | string = string>

Type Parameters

Parameter Constraint Default Description
TScope string | undefined string | undefined Scope added as a prefix to the name of every schema produced by this factory.
TName number | string string Type of names used to identify each schema produced in this factory. Typically this is just string but it is also possible to use string or number based enums if you prefer to identify your types that way.

Remarks

For details related to inputting data constrained by schema (including via assignment), and how non-exact schema types are handled in general refer to Input. For information about recursive schema support, see methods postfixed with "recursive" and ValidateRecursiveSchema. To apply schema defined with this factory to a tree, see viewWith(config) and TreeViewConfiguration.

All schema produced by this factory get a unique identifier by combining the scope with the schema's Name. The Name part may be explicitly provided as a parameter, or inferred as a structural combination of the provided types. The APIs which use this second approach, structural naming, also deduplicate all equivalent calls. Therefor two calls to array(allowedTypes) with the same allowedTypes will return the same TreeNodeSchema instance. On the other hand, two calls to array(name, allowedTypes) will always return different TreeNodeSchema instances and it is an error to use both in the same tree (since their identifiers are not unique).

For "customizable" schema (those which can be subclassed to customize them, see details below) some additional rules must be followed:

  1. Only a single schema can be used from the class hierarchy deriving from the base class produced by this factory. It is legal to subclass the returned class, and even subclass that class, but only a single class from that class hierarchy can ever be instantiated or passed to any API as a schema. These base classes can be used with instanceof, but not with schema based APIs like Tree.is. 2. If overriding the constructor, the constructor must accept the same argument as the base constructor super and forward it to super unchanged. 3. Properties for fields defined in the schema should not be overridden. 4. Additional static members added to schema should pick relatively unique keys to reduce the risk of colliding with implementation details what are not exposed in the API. 5. If exporting the schema from a package which uses API-Extractor, export the base class and derived class separately to work around [a known limitation](https://github.com/microsoft/rushstack/issues/4429).

Note: POJO stands for Plain Old JavaScript Object. This means an object that works like a {} style object literal. In this case it means the prototype is Object.prototype and acts like a set of key value pairs (data, not methods). The usage below generalizes this to include array and map like objects as well.

There are two ways to use these APIs:

Customizable Approach:

  1. Declaration: class X extends schemaFactory.object("x", {}) {}

  2. Allows adding "local" (non-persisted) members: Yes. Members (including methods) can be added to the class.

  3. Prototype: The user-defined class.

  4. Structurally named Schema: Not Supported.

  5. Explicitly named Objects: Supported.

  6. Explicitly named Maps and Arrays: Supported: Both declaration approaches can be used.

  7. Node.js assert.deepEqual: Compares like class instances: equal to other nodes of the same type with the same content, including custom local fields.

  8. IntelliSense: Shows and links to user-defined class by name: X.

  9. Recursion: Supported with special declaration patterns.

POJO Emulation Approach:

  1. Declaration: const X = schemaFactory.object("x", {}); type X = NodeFromSchema<typeof X>;

  2. Allows adding "local" (non-persisted) members: No. Attempting to set non-field members will result in an error.

  3. Prototype: Object.prototype, Map.prototype, or Array.prototype depending on node kind.

  4. Structurally named Schema: Supported.

  5. Explicitly named Objects: Supported.

  6. Explicitly named Maps and Arrays: Not Supported.

  7. Node.js assert.deepEqual: Compares like plain objects: equal to plain JavaScript objects with the same fields, and other nodes with the same fields, even if the types are different.

  8. IntelliSense: Shows internal type generation logic: object & TreeNode & ObjectFromSchemaRecord<{}> & WithType<"test.x">.

  9. Recursion: Unsupported: Generated .d.ts files replace recursive references with any, breaking the use of recursive schema across compilation boundaries.

Note that while "POJO Emulation" nodes act a lot like POJO objects, they are not true POJO objects:

  • Adding new arbitrary fields will error, as well some cases of invalid edits.

  • They are implemented using proxies.

  • They have state that is not exposed via enumerable own properties, including a TreeNodeSchema. This makes libraries like node.js assert.deepEqual fail to detect differences in type.

  • Assigning members has side effects (in this case editing the persisted/shared tree).

  • Not all operations implied by the prototype will work correctly: stick to the APIs explicitly declared in the TypeScript types.

Constructors

Constructor Description
(constructor)(scope) Construct a SchemaFactory with a given scope.

Static Properties

Property Modifiers Type Description
boolean readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown> TreeNodeSchema for holding a boolean.
handle readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown> TreeNodeSchema for holding an IFluidHandle.
leaves readonly readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>] AllowedTypes for holding any of the leaf types.
null readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown> TreeNodeSchema for JavaScript null.
number readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown> TreeNodeSchema for holding a JavaScript number.
optional readonly <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata> Make a field optional instead of the default, which is required.
optionalRecursive readonly <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T> schemaStatics.optional except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
required readonly <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata> Make a field explicitly required.
requiredRecursive readonly <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T> schemaStatics.required except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
string readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown> TreeNodeSchema for holding a JavaScript string.

Properties

Property Modifiers Type Description
boolean readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown> TreeNodeSchema for holding a boolean.
handle readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown> TreeNodeSchema for holding an IFluidHandle.
identifier readonly FieldSchema<FieldKind.Identifier, typeof this.string> A special field which holds a unique identifier for an object node.
leaves readonly readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>] AllowedTypes for holding any of the leaf types.
null readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown> TreeNodeSchema for JavaScript null.
number readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown> TreeNodeSchema for holding a JavaScript number.
optional readonly <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata> Make a field optional instead of the default, which is required.
optionalRecursive readonly <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T> schemaStatics.optional except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
required readonly <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata> Make a field explicitly required.
requiredRecursive readonly <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T> schemaStatics.required except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
scope readonly TScope Prefix appended to the identifiers of all TreeNodeSchema produced by this builder.
string readonly TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown> TreeNodeSchema for holding a JavaScript string.

Methods

Method Return Type Description
array(allowedTypes) TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined> Define a structurally typed TreeNodeSchema for a TreeArrayNode.
array(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined> Define (and add to this library) a TreeNodeSchemaClass for a TreeArrayNode.
arrayRecursive(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>; }, false, T, undefined> SchemaFactory.array except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
map(allowedTypes) TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined> Define a structurally typed TreeNodeSchema for a TreeMapNode.
map(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined> Define a TreeNodeSchema for a TreeMapNode.
mapRecursive(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T> ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>; }, false, T, undefined> SchemaFactory.map except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
object(name, fields) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNode<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecord<T>, true, T> Define a TreeNodeSchemaClass for a TreeObjectNode.
objectRecursive(name, t) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNodeUnsafe<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecordUnsafe<T>, false, T> object(name, fields) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Constructor Details

(constructor)

Construct a SchemaFactory with a given scope.

Signature

constructor(
scope: TScope);

Remarks

There are no restrictions on mixing schema from different schema factories. Typically each library will create one or more SchemaFactories and use them to define its schema.

Parameters

Parameter Type Description
scope TScope

Property Details

boolean

TreeNodeSchema for holding a boolean.

Signature

readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>

boolean

TreeNodeSchema for holding a boolean.

Signature

static readonly boolean: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>

handle

TreeNodeSchema for holding an IFluidHandle.

Signature

readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>

handle

TreeNodeSchema for holding an IFluidHandle.

Signature

static readonly handle: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>

identifier

A special field which holds a unique identifier for an object node.

Signature

get identifier(): FieldSchema<FieldKind.Identifier, typeof this.string>;

Type: FieldSchema<FieldKind.Identifier, typeof this.string>

Remarks

The value of this field, a "node identifier", uniquely identifies a node among all other nodes in the tree. Node identifiers are strings, and can therefore be used as lookup keys in maps or written to a database. When the node is constructed, the identifier field does not need to be populated. The SharedTree will provide an identifier for the node automatically. An identifier provided automatically by the SharedTree has the following properties: - It is a UUID. - It is compressed to a space-efficient representation when stored in the document. - A compressed form of the identifier can be accessed at runtime via the Tree.shortId() API. - It will error if read (and will not be present in the object's iterable properties) before the node has been inserted into the tree.

However, a user may alternatively supply their own string as the identifier if desired (for example, if importing identifiers from another system). In that case, it is up to the user to ensure that the identifier is unique within the current tree - no other node should have the same identifier at the same time. If the identifier is not unique, it may be read, but may cause libraries or features which operate over node identifiers to misbehave. User-supplied identifiers may be read immediately, even before insertion into the tree.

A node may have more than one identifier field (though note that this precludes the use of the Tree.shortId() API).

leaves

AllowedTypes for holding any of the leaf types.

Signature

readonly leaves: readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>];

Type: readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>]

leaves

AllowedTypes for holding any of the leaf types.

Signature

static readonly leaves: readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>];

Type: readonly [TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>, TreeNodeSchemaNonClass<"com.fluidframework.leaf.handle", NodeKind.Leaf, _dummyImport<unknown>, _dummyImport<unknown>, true, unknown, never, unknown>]

null

TreeNodeSchema for JavaScript null.

Signature

readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>

Remarks

There are good reasons to avoid using null in JavaScript, however sometimes it is desired. This TreeNodeSchema node provides the option to include nulls in trees when desired. Unless directly inter-operating with existing data using null, consider other approaches, like wrapping the value in an optional field, or using a more specifically named empty object node.

null

TreeNodeSchema for JavaScript null.

Signature

static readonly null: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null, true, unknown, never, unknown>

Remarks

There are good reasons to avoid using null in JavaScript, however sometimes it is desired. This TreeNodeSchema node provides the option to include nulls in trees when desired. Unless directly inter-operating with existing data using null, consider other approaches, like wrapping the value in an optional field, or using a more specifically named empty object node.

number

TreeNodeSchema for holding a JavaScript number.

Signature

readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>

Remarks

The number is a double-precision 64-bit binary format IEEE 754 value, however there are some exceptions: - NaN, and the infinities are converted to null (and may therefore only be used where null is allowed by the schema). - -0 may be converted to 0 in some cases.

These limitations match the limitations of JSON.

number

TreeNodeSchema for holding a JavaScript number.

Signature

static readonly number: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number, true, unknown, never, unknown>

Remarks

The number is a double-precision 64-bit binary format IEEE 754 value, however there are some exceptions: - NaN, and the infinities are converted to null (and may therefore only be used where null is allowed by the schema). - -0 may be converted to 0 in some cases.

These limitations match the limitations of JSON.

optional

Make a field optional instead of the default, which is required.

Signature

readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata>;

Type: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata>

optional

Make a field optional instead of the default, which is required.

Signature

static readonly optional: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata>;

Type: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Optional, T, TCustomMetadata>

optionalRecursive

schemaStatics.optional except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

readonly optionalRecursive: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T>;

Type: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T>

Remarks

This version of schemaStatics.optional has fewer type constraints to work around TypeScript limitations, see Unenforced. See ValidateRecursiveSchema for additional information about using recursive schema.

optionalRecursive

schemaStatics.optional except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

static readonly optionalRecursive: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T>;

Type: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Optional, T>

Remarks

This version of schemaStatics.optional has fewer type constraints to work around TypeScript limitations, see Unenforced. See ValidateRecursiveSchema for additional information about using recursive schema.

required

Make a field explicitly required.

Signature

readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata>;

Type: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata>

Remarks

Fields are required by default, but this API can be used to make the required nature explicit in the schema, and allows associating custom properties with the field.

required

Make a field explicitly required.

Signature

static readonly required: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata>;

Type: <const T extends ImplicitAllowedTypes, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => FieldSchema<FieldKind.Required, T, TCustomMetadata>

Remarks

Fields are required by default, but this API can be used to make the required nature explicit in the schema, and allows associating custom properties with the field.

requiredRecursive

schemaStatics.required except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

readonly requiredRecursive: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T>;

Type: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T>

Remarks

This version of schemaStatics.required has fewer type constraints to work around TypeScript limitations, see Unenforced. See ValidateRecursiveSchema for additional information about using recursive schema.

requiredRecursive

schemaStatics.required except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

static readonly requiredRecursive: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T>;

Type: <const T extends unknown>(t: T, props?: Omit<FieldProps<unknown>, "defaultProvider"> | undefined) => FieldSchemaUnsafe<FieldKind.Required, T>

Remarks

This version of schemaStatics.required has fewer type constraints to work around TypeScript limitations, see Unenforced. See ValidateRecursiveSchema for additional information about using recursive schema.

scope

Prefix appended to the identifiers of all TreeNodeSchema produced by this builder.

Signature

readonly scope: TScope;

Type: TScope

Remarks

Generally each independently developed library (possibly a package, but could also be part of a package or multiple packages developed together) should get its own unique scope. Then each schema in the library get a name which is unique within the library. The scope and name are joined (with a period) to form the schema identifier. Following this pattern allows a single application to depend on multiple libraries which define their own schema, and use them together in a single tree without risk of collisions. If a library logically contains sub-libraries with their own schema, they can be given a scope nested inside the parent scope, such as "ParentScope.ChildScope".

To avoid collisions between the scopes of libraries it is recommended that the libraries use Reverse domain name notation or a UUIDv4 for their scope. If this pattern is followed, application can safely use third party libraries without risk of the schema in them colliding.

You may opt out of using a scope by passing undefined, but note that this increases the risk of collisions.

Usage

Example 1

Fluid Framework follows this pattern, placing the schema for the built in leaf types in the com.fluidframework.leaf scope. If Fluid Framework publishes more schema in the future, they would be under some other com.fluidframework scope. This ensures that any schema defined by any other library will not conflict with Fluid Framework's schema as long as the library uses the recommended patterns for how to scope its schema..

Example 2

A library could generate a random UUIDv4, like 242c4397-49ed-47e6-8dd0-d5c3bc31778b and use that as the scope. Note: do not use this UUID: a new one must be randomly generated when needed to ensure collision resistance.

const factory = new SchemaFactory("242c4397-49ed-47e6-8dd0-d5c3bc31778b");

string

TreeNodeSchema for holding a JavaScript string.

Signature

readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>

Remarks

Strings containing unpaired UTF-16 surrogate pair code units may not be handled correctly.

These limitations come from the use of UTF-8 encoding of the strings, which requires them to be valid unicode. JavaScript does not make this requirement for its strings so not all possible JavaScript strings are supported.

string

TreeNodeSchema for holding a JavaScript string.

Signature

static readonly string: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>;

Type: TreeNodeSchemaNonClass<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string, true, unknown, never, unknown>

Remarks

Strings containing unpaired UTF-16 surrogate pair code units may not be handled correctly.

These limitations come from the use of UTF-8 encoding of the strings, which requires them to be valid unicode. JavaScript does not make this requirement for its strings so not all possible JavaScript strings are supported.

Method Details

array

Define a structurally typed TreeNodeSchema for a TreeArrayNode.

Signature

array<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined>;
Type Parameters
Parameter Constraint Description
T TreeNodeSchema | readonly TreeNodeSchema[]

Remarks

The identifier for this Array is defined as a function of the provided types. It is still scoped to this SchemaFactory, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing. This does not support recursive types.

If using these structurally named arrays, other types in this schema builder should avoid names of the form Array<${string}>.

Example

The returned schema should be used as a schema directly:

const MyArray = factory.array(factory.number);
type MyArray = NodeFromSchema<typeof MyArray>;

Or inline:

factory.object("Foo", {myArray: factory.array(factory.number)});

Parameters

Parameter Type Description
allowedTypes T The types that may appear in the array.

Returns

Return type: TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined>

array

Define (and add to this library) a TreeNodeSchemaClass for a TreeArrayNode.

Signature

array<const Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined>;
Type Parameters
Parameter Constraint Description
Name TName
T ImplicitAllowedTypes

Example

class NamedArray extends factory.array("name", factory.number) {}

Parameters

Parameter Type Description
name Name Unique identifier for this schema within this factory's scope.
allowedTypes T The types that may appear in the array.

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T, undefined>

arrayRecursive

SchemaFactory.array except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

arrayRecursive<const Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array, unknown>, {
[Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>;
}, false, T, undefined>;
Type Parameters
Parameter Constraint Description
Name TName
T Unenforced<ImplicitAllowedTypes>

Remarks

This version of SchemaFactory.array uses the same workarounds as objectRecursive(name, t). See ValidateRecursiveSchema for additional information about using recursive schema.

Parameters

Parameter Type Description
name Name
allowedTypes T

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Array, unknown>, { [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>; }, false, T, undefined>

map

Define a structurally typed TreeNodeSchema for a TreeMapNode.

Signature

map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined>;
Type Parameters
Parameter Constraint Description
T TreeNodeSchema | readonly TreeNodeSchema[]

Remarks

The unique identifier for this Map is defined as a function of the provided types. It is still scoped to this SchemaBuilder, but multiple calls with the same arguments will return the same schema object, providing somewhat structural typing. This does not support recursive types.

If using these structurally named maps, other types in this schema builder should avoid names of the form Map<${string}>.

Example

The returned schema should be used as a schema directly:

const MyMap = factory.map(factory.number);
type MyMap = NodeFromSchema<typeof MyMap>;

Or inline:

factory.object("Foo", {myMap: factory.map(factory.number)});

Parameters

Parameter Type Description
allowedTypes T The types that may appear as values in the map.

Returns

Return type: TreeNodeSchemaNonClass<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined>

map

Define a TreeNodeSchema for a TreeMapNode.

Signature

map<Name extends TName, const T extends ImplicitAllowedTypes>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined>;
Type Parameters
Parameter Constraint Description
Name TName
T ImplicitAllowedTypes

Example

class NamedMap extends factory.map("name", factory.number) {}

Parameters

Parameter Type Description
name Name Unique identifier for this schema within this factory's scope.
allowedTypes T The types that may appear as values in the map.

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map>, MapNodeInsertableData<T>, true, T, undefined>

mapRecursive

SchemaFactory.map except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

mapRecursive<Name extends TName, const T extends Unenforced<ImplicitAllowedTypes>>(name: Name, allowedTypes: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map, unknown>, {
[Symbol.iterator](): Iterator<[
string,
InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>
]>;
} | {
readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>;
}, false, T, undefined>;
Type Parameters
Parameter Constraint Description
Name TName
T Unenforced<ImplicitAllowedTypes>

Remarks

This version of SchemaFactory.map uses the same workarounds as objectRecursive(name, t). See ValidateRecursiveSchema for additional information about using recursive schema.

Parameters

Parameter Type Description
name Name
allowedTypes T

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>, NodeKind.Map, unknown>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T> ]>; } | { readonly [x: string]: InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>; }, false, T, undefined>

object

Define a TreeNodeSchemaClass for a TreeObjectNode.

Signature

object<const Name extends TName, const T extends RestrictiveStringRecord<ImplicitFieldSchema>>(name: Name, fields: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNode<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecord<T>, true, T>;
Type Parameters
Parameter Constraint Description
Name TName
T RestrictiveStringRecord<ImplicitFieldSchema>

Parameters

Parameter Type Description
name Name Unique identifier for this schema within this factory's scope.
fields T Schema for fields of the object node's schema. Defines what children can be placed under each key.

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNode<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecord<T>, true, T>

objectRecursive

object(name, fields) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

objectRecursive<const Name extends TName, const T extends Unenforced<RestrictiveStringRecord<ImplicitFieldSchema>>>(name: Name, t: T): TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNodeUnsafe<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecordUnsafe<T>, false, T>;
Type Parameters
Parameter Constraint Description
Name TName
T Unenforced<RestrictiveStringRecord<ImplicitFieldSchema>>

Remarks

This version of object(name, fields) has fewer type constraints to work around TypeScript limitations, see Unenforced. See ValidateRecursiveSchema for additional information about using recursive schema.

Additionally ImplicitlyConstructable is disabled (forcing use of constructor) to avoid error TS2589: Type instantiation is excessively deep and possibly infinite. which otherwise gets reported at sometimes incorrect source locations that vary based on incremental builds.

Parameters

Parameter Type Description
name Name
t T

Returns

Return type: TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Object, TreeObjectNodeUnsafe<T, ScopedSchemaName<TScope, Name>>, object & InsertableObjectFromSchemaRecordUnsafe<T>, false, T>

See Also

SchemaFactoryAlpha