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> extends SchemaFactory_base
Extends: SchemaFactory_base
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 TreeViewConfiguration and viewWith(config). See the documentation on schema evolution for how to handle changes to schema over time.
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. Therefore 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
superand forward it tosuperunchanged.
- 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.
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: additional 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>;
- Does not allow adding "local" (non-persisted) members: attempting to set non-field members will result in an error.
- Prototype:
Object.prototype,Map.prototype, orArray.prototypedepending 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 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.deepEqualfail 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.