UNPKG

react-native-nitro-modules

Version:

Insanely fast native C++, Swift or Kotlin modules with a statically compiled binding layer to JSI.

70 lines (64 loc) 2.52 kB
import type { HybridObject } from './HybridObject' import { NitroModules } from './NitroModules' const cache = new Map<string, Function>() /** * Get a constructor function for the given `HybridObject` {@linkcode T}. * @param name The name of the `HybridObject` under which it was registered at. * @returns A constructor that creates instances of {@linkcode T} * @example * ```ts * export const HybridImage = getHybridObjectConstructor<Image>('Image') * * const image1 = new HybridImage() * const image2 = new HybridImage() * image1 instanceof HybridImage // --> true * ``` */ export function getHybridObjectConstructor<T extends HybridObject<{}>>( name: string ): { new (): T } { // Cache functions for performance. if (cache.has(name)) { return cache.get(name) as { new (): T } } // A function that creates the HybridObject. // This can be called with `new`, and internally sets the prototype. const constructorFunc = function () { const instance = NitroModules.createHybridObject<T>(name) const prototype = Object.getPrototypeOf(instance) if (constructorFunc.prototype !== prototype) { constructorFunc.prototype = prototype constructorFunc.prototypeInitialized = true } return instance } as unknown as { new (): T } & { prototypeInitialized?: boolean } // Configure lazy prototype. If `instanceof` is called before a `T` // has been created, we just lazy-create a new `T` instance to set the proto. constructorFunc.prototypeInitialized = false Object.defineProperty(constructorFunc, Symbol.hasInstance, { value: (instance: unknown) => { if (!constructorFunc.prototypeInitialized) { // User didn't call `new T()` yet, so we don't // know the prototype yet. Just create one temp object to find // out the prototype. const tempInstance = NitroModules.createHybridObject<T>(name) constructorFunc.prototype = Object.getPrototypeOf(tempInstance) constructorFunc.prototypeInitialized = true } // Loop through the prototype chain of the value // we're testing for to see if it is a direct instance // of `T`, or a derivative of it. let proto = Object.getPrototypeOf(instance) while (proto != null) { if (proto === constructorFunc.prototype) { return true } proto = Object.getPrototypeOf(proto) } // No prototype overlap. return false }, }) cache.set(name, constructorFunc) return constructorFunc }