SchemaFactory Class
Creates various types of schema for TreeNodes.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
/** @sealed */
export declare class SchemaFactory<out TScope extends string | undefined = string | undefined, TName extends number | string = string> implements SchemaStatics
Implements: SchemaStatics
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:
-
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 likeTree.is
. -
If overriding the constructor, the constructor must accept the same argument as the base constructor
super
and forward it tosuper
unchanged. -
Properties for fields defined in the schema should not be overridden.
-
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.
-
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:
-
Declaration:
class X extends schemaFactory.object("x", {}) {}
-
Allows adding "local" (non-persisted) members: Yes. Members (including methods) can be added to the class.
-
Prototype: The user-defined class.
-
Structurally named Schema: Not Supported.
-
Explicitly named Objects: Supported.
-
Explicitly named Maps and Arrays: Supported: Both declaration approaches can be used.
-
Node.js
assert.deepEqual
: Compares like class instances: equal to other nodes of the same type with the same content, including custom local fields. -
IntelliSense: Shows and links to user-defined class by name:
X
. -
Recursion: Supported with special declaration patterns.
POJO Emulation Approach:
-
Declaration:
const X = schemaFactory.object("x", {}); type X = NodeFromSchema<typeof X>;
-
Allows adding "local" (non-persisted) members: No. Attempting to set non-field members will result in an error.
-
Prototype:
Object.prototype
,Map.prototype
, orArray.prototype
depending on node kind. -
Structurally named Schema: Supported.
-
Explicitly named Objects: Supported.
-
Explicitly named Maps and Arrays: Not Supported.
-
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. -
IntelliSense: Shows internal type generation logic:
object & TreeNode & ObjectFromSchemaRecord<{}> & WithType<"test.x">
. -
Recursion: Unsupported: [Generated
.d.ts
files replace recursive references withany
](https://github.com/microsoft/TypeScript/issues/55832), 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 |
LeafSchema<"boolean", boolean> | TreeNodeSchema for holding a boolean. |
handle | readonly |
LeafSchema<"handle", IFluidHandle<unknown>> | TreeNodeSchema for holding an IFluidHandle. |
leaves | readonly |
readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>] | AllowedTypes for holding any of the leaf types. |
null | readonly |
LeafSchema<"null", null> | TreeNodeSchema for JavaScript null . |
number | readonly |
LeafSchema<"number", number> | 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 System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => System_Unsafe.FieldSchemaUnsafe<FieldKind.Optional, T, TCustomMetadata> | 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 System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => System_Unsafe.FieldSchemaUnsafe<FieldKind.Required, T, TCustomMetadata> | required except tweaked to work better for recursive types. Use with ValidateRecursiveSchema for improved type safety. |
string | readonly |
LeafSchema<"string", string> | TreeNodeSchema for holding a JavaScript string . |
Properties
Property | Modifiers | Type | Description |
---|---|---|---|
boolean | readonly |
LeafSchema<"boolean", boolean> | TreeNodeSchema for holding a boolean. |
handle | readonly |
LeafSchema<"handle", IFluidHandle<unknown>> | TreeNodeSchema for holding an IFluidHandle. |
identifier | readonly |
FieldSchema<FieldKind.Identifier, typeof this.string> | A special readonly field which holds an identifier string for an object node. |
leaves | readonly |
readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>] | AllowedTypes for holding any of the leaf types. |
null | readonly |
LeafSchema<"null", null> | TreeNodeSchema for JavaScript null . |
number | readonly |
LeafSchema<"number", number> | 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 System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => System_Unsafe.FieldSchemaUnsafe<FieldKind.Optional, T, TCustomMetadata> | 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 System_Unsafe.ImplicitAllowedTypesUnsafe, const TCustomMetadata = unknown>(t: T, props?: Omit<FieldProps<TCustomMetadata>, "defaultProvider"> | undefined) => System_Unsafe.FieldSchemaUnsafe<FieldKind.Required, T, TCustomMetadata> | 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 |
LeafSchema<"string", string> | TreeNodeSchema for holding a JavaScript string . |
Methods
Constructor Details
(constructor)
Construct a SchemaFactory with a given scope.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
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.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
readonly boolean: LeafSchema<"boolean", boolean>;
Type: LeafSchema<"boolean", boolean>
boolean
TreeNodeSchema for holding a boolean.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
static readonly boolean: LeafSchema<"boolean", boolean>;
Type: LeafSchema<"boolean", boolean>
handle
TreeNodeSchema for holding an IFluidHandle.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
readonly handle: LeafSchema<"handle", IFluidHandle<unknown>>;
Type: LeafSchema<"handle", IFluidHandle<unknown>>
handle
TreeNodeSchema for holding an IFluidHandle.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
static readonly handle: LeafSchema<"handle", IFluidHandle<unknown>>;
Type: LeafSchema<"handle", IFluidHandle<unknown>>
identifier
A special readonly field which holds an identifier string for an object node.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
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", is a string which identifies a node (or nodes) among all 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 specified. When an identifier is not provided, the SharedTree will generate an identifier for the node automatically. The identifier generated by the SharedTree has the following properties:
-
It is a UUID which will not collide with other generated UUIDs.
-
It is compressed to a space-efficient representation when stored in the document. Reading the identifier before inserting the node into a tree prevents the identifier from being stored in its compressed form, resulting in a larger storage footprint.
-
A compressed form of the identifier can be accessed at runtime via the Tree.shortId() API.
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, if the user requires it to be unique, it is up to them to ensure uniqueness. 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.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
readonly leaves: readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>];
Type: readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>]
leaves
AllowedTypes for holding any of the leaf types.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
static readonly leaves: readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>];
Type: readonly [LeafSchema<"string", string>, LeafSchema<"number", number>, LeafSchema<"boolean", boolean>, LeafSchema<"null", null>, LeafSchema<"handle", IFluidHandle<unknown>>]
null
TreeNodeSchema for JavaScript null
.
This type is "sealed," meaning that code outside of the library defining it should not implement or extend it. Future versions of this type may add members or make typing of readonly members more specific.
Signature
readonly null: LeafSchema<"null", null>;
Type: LeafSchema<"null", null>