Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

instanceof SerializableResource #37

Open
plojo opened this issue Oct 17, 2024 · 1 comment
Open

instanceof SerializableResource #37

plojo opened this issue Oct 17, 2024 · 1 comment
Assignees
Labels
discussion enhancement New feature or request

Comments

@plojo
Copy link
Collaborator

plojo commented Oct 17, 2024

After some consideration, I came up with the following idea to enable the usage of the instanceof keyword with SerializableResource. This approach leverages decorators and metadata.

We define SerializableResource as an abstract class. Abstract classes can be used similarly to interfaces through the implements keyword. Additionally, we apply a decorator to our class, which will be explained below:

Example:

@SerializableResource.register
export class Material extends Mutable implements SerializableResource {}

The abstract class SerializableResource now allows us to achieve two things:

  1. Encapsulate a decorator (register) that registers the class, using the class's metadata to indicate that it implements SerializableResource.
  2. Override [Symbol.hasInstance] (instanceof behavior) to check the metadata of a given instance to verify whether it implements SerializableResource.

SerializableResource:

export abstract class SerializableResource implements Serializable {
  public abstract name: string;
  public abstract idResource: string;
  public abstract readonly type: string;

  // decorator
  public static register(_class: abstract new (...args: General[]) => SerializableResource, _context: ClassDecoratorContext): void {
    let meta: Metadata = _context.metadata;
    meta.implements ??= [];
    meta.implements.push(SerializableResource);
  }

  // instanceof
  public static [Symbol.hasInstance](_instance: unknown): _instance is SerializableResource {
    if (Function.prototype[Symbol.hasInstance].call(SerializableResource, _instance)) // default instanceof behavior
      return true;

    let meta: Metadata = _instance.constructor[Symbol.metadata]; // check the metadata
    return meta?.implements?.includes(SerializableResource);
  }

  public abstract serialize(): Serialization;
  public abstract deserialize(_serialization: Serialization): Promise<Serializable>;
}

To make this work, we need to decorate our class with @SerializableResource.register (see Example). Once the class is registered, we can now do the following:

Let instance: Material = new Material("Material");
// check instance
instance instanceof SerializableResource // true
// check class
Material.prototype instanceof SerializableResource // true

Note: We could expand this pattern to allow the registration of custom resources compatible with the editor. The abstract class could keep track of all registered SerializableResources, enabling creators to register their own custom SerializableResources.

@plojo plojo added enhancement New feature or request discussion labels Oct 17, 2024
@JirkaDellOro
Copy link
Member

Well... errr... sounds good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants