Packages > fluid-framework > SchemaFactory

SchemaFactory Class

Creates various types of schema for TreeNode s.

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

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).

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 | POJO Emulation | | ------------------- | ------------ |--------------- | | Declaration | class X extends schemaFactory.object("x", {}) {} | const X = schemaFactory.object("x", {}); type X = NodeFromSchema<typeof X>; | Allows adding “local” (non-persisted) members | Yes. Members (including methods) can be added to class. | No. Attempting to set non-field members will error. | | Prototype | The user defined class | Object.prototype, Map.prototype or Array.prototype depending on node kind | | Structurally named Schema | Not Supported | Supported | | Explicitly named Objects | Supported | Supported | | Explicitly named Maps and Arrays | Supported: Both declaration approaches can be used | Not Supported | | node.js assert.deepEqual | Compares like class instances: equal to other nodes of the same type with the same content, including custom local fields. | 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. | | IntelliSense | Shows and links to user defined class by name: X | Shows internal type generation logic: object & TreeNode & ObjectFromSchemaRecord<{}> & WithType<"test.x"> | | Recursion | Supported with special declaration patterns. | Unsupported: Generated d.ts files replace recursive references with any, breaking 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) Constructs a new instance of the SchemaFactory class

Properties

Property Modifiers Type Description
boolean readonly TreeNodeSchema<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean> TreeNodeSchema for holding a boolean.
handle readonly TreeNodeSchema<"com.fluidframework.leaf.handle", NodeKind.Leaf, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>> TreeNodeSchema for holding an IFluidHandle.
identifier readonly FieldSchema<FieldKind.Identifier> Make a field of type identifier instead of the default which is required.
null readonly TreeNodeSchema<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null> TreeNodeSchema for JavaScript null.
number readonly TreeNodeSchema<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number> TreeNodeSchema for holding a JavaScript number.
scope readonly TScope
string readonly TreeNodeSchema<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string> TreeNodeSchema for holding a JavaScript string.

Methods

Method Return Type Description
array(allowedTypes) TreeNodeSchema<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T> Define a structurally typed TreeNodeSchema for a TreeArrayNode.
array(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, Name>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T> 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>>, { [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>; }, false, T> SchemaFactory.array except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
map(allowedTypes) TreeNodeSchema<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T> Define a structurally typed TreeNodeSchema for a TreeMapNode.
map(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, Name>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T> Define a TreeNodeSchema for a TreeMapNode.
mapRecursive(name, allowedTypes) TreeNodeSchemaClass<ScopedSchemaName<TScope, Name>, NodeKind.Map, TreeMapNodeUnsafe<T> & WithType<ScopedSchemaName<TScope, Name>>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T> ]>; }, false, T> 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 TreeNodeSchema 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.
optional(t, props) FieldSchema<FieldKind.Optional, T> Make a field optional instead of the default, which is required.
optionalRecursive(t, props) FieldSchemaUnsafe<FieldKind.Optional, T> optional(t, props) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.
required(t, props) FieldSchema<FieldKind.Required, T> Make a field explicitly required.
requiredRecursive(t, props) FieldSchemaUnsafe<FieldKind.Required, T> required(t, props) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Constructor Details

(constructor)

Constructs a new instance of the SchemaFactory class

Signature

constructor(scope: TScope);

Parameters

Parameter Type Description
scope TScope Prefix appended to the identifiers of all TreeNodeSchema produced by this builder. Use of [Reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) or a UUIDv4 is recommended to avoid collisions. You may opt out of using a scope by passing undefined, but note that this increases the risk of collisions.

Property Details

boolean

TreeNodeSchema for holding a boolean.

Signature

readonly boolean: TreeNodeSchema<"com.fluidframework.leaf.boolean", NodeKind.Leaf, boolean, boolean>;

handle

TreeNodeSchema for holding an IFluidHandle .

Signature

readonly handle: TreeNodeSchema<"com.fluidframework.leaf.handle", NodeKind.Leaf, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>, import("@fluidframework/core-interfaces").IFluidHandle<import("@fluidframework/core-interfaces").FluidObject & import("@fluidframework/core-interfaces").IFluidLoadable>>;

identifier

Make a field of type identifier instead of the default which is required.

Signature

get identifier(): FieldSchema<FieldKind.Identifier>;

null

TreeNodeSchema for JavaScript null.

Signature

readonly null: TreeNodeSchema<"com.fluidframework.leaf.null", NodeKind.Leaf, null, null>;

Remarks

There are good [reasons to avoid using null](https://www.npmjs.com/package/%40rushstack/eslint-plugin #rushstackno-new-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: TreeNodeSchema<"com.fluidframework.leaf.number", NodeKind.Leaf, number, number>;

Remarks

The number is a [double-precision 64-bit binary format IEEE 754](https://en.wikipedia.org/wiki/Double-precision _floating-point_format) 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.

scope

Signature

readonly scope: TScope;

string

TreeNodeSchema for holding a JavaScript string.

Signature

readonly string: TreeNodeSchema<"com.fluidframework.leaf.string", NodeKind.Leaf, string, string>;

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): TreeNodeSchema<ScopedSchemaName<TScope, `Array<${string}>`>, NodeKind.Array, TreeArrayNode<T> & WithType<ScopedSchemaName<TScope, `Array<${string}>`>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
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

Returns

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

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>>, Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T>>, true, T>;
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

Returns

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

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>>, {
        [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>>;
    }, false, T>;
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>>, { [Symbol.iterator](): Iterator<InsertableTreeNodeFromImplicitAllowedTypesUnsafe <T>>; }, false, T>

map

Define a structurally typed TreeNodeSchema for a TreeMapNode .

Signature

map<const T extends TreeNodeSchema | readonly TreeNodeSchema[]>(allowedTypes: T): TreeNodeSchema<ScopedSchemaName<TScope, `Map<${string}>`>, NodeKind.Map, TreeMapNode<T> & WithType<ScopedSchemaName<TScope, `Map<${string}>`>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T>;
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

Returns

Return type: TreeNodeSchema <ScopedSchemaName <TScope, `Map<${string}>`>, NodeKind.Map , TreeMapNode <T> & WithType <ScopedSchemaName <TScope, `Map<${string}>`>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes <T>]>, true, T>

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>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes<T>]>, true, T>;
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

Returns

Return type: TreeNodeSchemaClass <ScopedSchemaName <TScope, Name>, NodeKind.Map , TreeMapNode <T> & WithType <ScopedSchemaName <TScope, Name>>, Iterable<[string, InsertableTreeNodeFromImplicitAllowedTypes <T>]>, true, T>

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>>, {
        [Symbol.iterator](): Iterator<[
            string,
            InsertableTreeNodeFromImplicitAllowedTypesUnsafe<T>
        ]>;
    }, false, T>;
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>>, { [Symbol.iterator](): Iterator<[ string, InsertableTreeNodeFromImplicitAllowedTypesUnsafe <T> ]>; }, false, T>

object

Define a TreeNodeSchema for a TreeObjectNode .

Signature

object<const Name extends TName, const T extends RestrictiveReadonlyRecord<string, 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 RestrictiveReadonlyRecord<string, 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<RestrictiveReadonlyRecord<string, 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<RestrictiveReadonlyRecord<string, 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>

optional

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

Signature

optional<const T extends ImplicitAllowedTypes>(t: T, props?: FieldProps): FieldSchema<FieldKind.Optional, T>;
Type Parameters
Parameter Constraint Description
T ImplicitAllowedTypes

Parameters

Parameter Modifiers Type Description
t T The types allowed under the field.
props optional FieldProps Optional properties to associate with the field.

Returns

Return type: FieldSchema <FieldKind.Optional , T>

optionalRecursive

optional(t, props) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

optionalRecursive<const T extends Unenforced<ImplicitAllowedTypes>>(t: T, props?: FieldProps): FieldSchemaUnsafe<FieldKind.Optional, T>;
Type Parameters
Parameter Constraint Description
T Unenforced<ImplicitAllowedTypes>

Remarks

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

Parameters

Parameter Modifiers Type Description
t T
props optional FieldProps

Returns

Return type: FieldSchemaUnsafe <FieldKind.Optional , T>

required

Make a field explicitly required.

Signature

required<const T extends ImplicitAllowedTypes>(t: T, props?: FieldProps): FieldSchema<FieldKind.Required, T>;
Type Parameters
Parameter Constraint Description
T ImplicitAllowedTypes

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.

Parameters

Parameter Modifiers Type Description
t T The types allowed under the field.
props optional FieldProps Optional properties to associate with the field.

Returns

Return type: FieldSchema <FieldKind.Required , T>

requiredRecursive

required(t, props) except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety.

Signature

requiredRecursive<const T extends Unenforced<ImplicitAllowedTypes>>(t: T, props?: FieldProps): FieldSchemaUnsafe<FieldKind.Required, T>;
Type Parameters
Parameter Constraint Description
T Unenforced<ImplicitAllowedTypes>

Remarks

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

Parameters

Parameter Modifiers Type Description
t T
props optional FieldProps

Returns

Return type: FieldSchemaUnsafe <FieldKind.Required , T>