Skip to content

Instantly share code, notes, and snippets.

@lilBunnyRabbit
Last active June 5, 2023 13:01
Show Gist options
  • Select an option

  • Save lilBunnyRabbit/222cc5d5c48d1912bc46821c77cca947 to your computer and use it in GitHub Desktop.

Select an option

Save lilBunnyRabbit/222cc5d5c48d1912bc46821c77cca947 to your computer and use it in GitHub Desktop.
React service | Brainstorming
export class ExampleService extends Service {
readonly startExample = this.observable(this._startExample);
private _startExample(
observer: ServiceObserver<{
progress: number;
}>,
test: string
): string {
observer.dispatch("progress", 1);
return test;
}
readonly startAsyncExample = this.observable(this._startAsyncExample);
private async _startAsyncExample(
observer: ServiceObserver<{
progress: number;
}>,
test: string
): Promise<string> {
observer.dispatch("progress", 1);
return test;
}
}
export default new ExampleService();
// Example usage
// TS Playground: https://www.typescriptlang.org/play?#code/C4TwDgpgBAyhBOA3AlgYwgUURAdsAwgIYA2xARoagNYA8AKgHxQC8UAFBNngFxT4CuAZ2AB7ALZZcwegwCULJohHIAJgG4AsAChtEAB5gR8YFFTFCgwbAQp0AeTKCbCepLxX9wXCqsAlCKhGKjTC8Mg4AOYANFCEOCBMrP6B8MGh4dGx8QxMnt5WbsB0hPARECYA3tpQUAD0AFT11TX1UADiuAgkUAjwRlAAZv04IiaC-GCGxhAqUGLlABYiPgB0zVD1tc1gYYiEXlDC+2hQAHKjMBNTXioY8H3wbDiE87zpkTHwEGDm6PN4pxeEDewDCkXkVS0NRqX2A-HgOCgOAgAHcoHcHmx1tCAAYAIgAJBU4Eg0BAHE4kAgVs95gBfFZE2kQOl4qDIKwjMZXIw3FZQAAKxAgFmgQmghOJNjJFOc8BpQIZRK+P0oEH+wEB9LxKxx2NkmihUDp2maDSaRo2UDo4BmUBR8EIkwQg36OMKxVK5RWKg5YH2qAWhRxa0tm22-DIxBOvsE-uAgfoPT0XhwPigVAgIBEA2thUEDDYoEgvDoMRU5UIyGIpfzAG06ABdWS8MgiETCuJQSHQqCw+GI8aQeWx+OBwpPVF8ISiCRcYBF22xKzvTIVKAV4BV4jG2QG5omnRG83rVoAAQrOwC+ztAFozqNDjzpip+UKRU4oOKoDiSbZyY4co+n6AYLCGp5bEaIjYPcqjQKOoETgA+pwUi8IULZQG2HYioiPbQsACx9Gif4yoBVLyucwCXJMvIzBiRhFgsHLAXGiHzgq8wxIRLEIQmCycRA+5GoeZqNKe1q2rMDpOsOrrwD+HolGUwArIQKgqAAMhyqYIOBYaQTUYCRtGqCxBp2nCJ08BJnkaZWJm2a5nQ+aFtixbAtaUTYqgJDkJQVC8KR6CFEQpAUNQrjzoIDaNkwAA+SL8KQ3mWlAIhgMAyAiDgggAPytu2naIolACCGmFJZunwHYmXZblUCJfwaYQAM4QzM0mE8VY+E1EO1Lqbc85VdZi6QMuhyghkMS+eFAUTZVOnWTEGVZTlgjCb2-YIlA3WGjUonHuJYZQBe3xfL5NxQPeVFPrRL5vp2n7fr+0r2ORMFqRZS3IvA+nQuGUEwWEFbmUNUgjb9WJpUhHkgmC0TYkhs3+dQ6HDT9CB2PAi1Wb9DgAFYBCYiU4MlxCpb2SGrfV+WFThXZlRVGN41jdXrY1X4tW1yIqJ1vBKKo3buURIgkW9AGUp9VE0dc9H3Ix3VfeDeCQ9SzLccxgjK2r8rMptxqmkdFoA5JkDSY6zoKUMCnuvOnoqSsXxiNBmAs9V-0tIZUDGVGJzO67uu2Sm+QZlmOZ5tFblpXDXk+X5EWBdYpIhfOYWo7QLnRbFCVJSl2I0+tBVYUVuGc7j1W1WtDVNdz7V80aXVa8LaX9fKAfYBXo0eRNq4zQn80WOi7vLel7O5QbMLlAOu1a-thtHjUJ4nWdV6XXeD7cvdfKCk9Yqfq9KeS0BHcQLrnsbN7ruwaDp9d1DSOx33SMo4n6MQ5jNU4yP+NkETqAkzzhTJGhdcrF2wsVcuP82bVysLXCsPMOqNwFsoWYvVZ7EWTv+WUFEVgy2fDcBijwlZ32gXrIEmsWKn11oJA2h5Dr6GuKYcwlgsFkhbkZPoXgAF2hEB9QgUYIA0GxHQHBMFkypnTMFY+FFKbQjoKVUoHgQ72SyCAOsjY5E1DoP4cYxATB2XTM1KgIwUQlUFH0MQHIhHGNMTgBgzRCyvwCrwNgfCpYIFLGIhAMQVh+OUoIUsiiIgbQUNaXRyVgAQmxNtREbA-FqSUUEpR8hmBMHQTUQIuUTDuLlCwJEU5pHeMePIIe5wcCnHJgI4U9BikMHnr2LJwgoB7GIPwaArBnHUDcR9HxUAEkBMntCWJ3Z0q9PgDEVp7TjQNJmQebQDCDC8mYRYAoegXg-AgNIiRodtn4S+OpHKxAQCTRKMADA6yxCbPyUrXJSBqkQCYixJCRxjAXI2cKA2OxkB7AOC8rcbzLmbOhr2O5MEgoS2KTQDJPs+gRC+JYXgZMxBkAQLMukDAtG7QgMIeGGR+aTQRhw6EYLqR8UDGwPEOwRDwpxYIPEMQACMQyRleGEPPQ6U9Dk4GOac4wpVBAgBwKgd5VzhQ3K1isMFDynna3+WcgVQqRVAs+fPb5vzoAWCVVAeV-LBXCtFcCgu4yIVHyhTC6ltLEVJRRWi7EGKsVsuAHiyIBKBSWOsSEKakR0nGo8SOEC-FKWWoRfSplLLp47SdRyhZRtzSNATYmpNybE3ohVdAFNmas2NEgk0sYEt8nIjRIa4U0i2DCW0FLMkKxXnnPTZSvEsgpXjJ1p-YNcLQ0MvYOuTc25dxhKaThFYxAaVsBxO6mlobeBEl7dWOkOI9yGiregGtALgCKoNfWvEjaVhTIgCsQiuA2BsD3akpgg7hTDtHTiAAaiQdp06Kh7vnYuoAA
const service = new ExampleService();
service.startExample("").observer.addListener("progress", ({ detail }) => console.log(`Progress: ${detail}`));
service.startAsyncExample("").value.then((value) => console.log(`Value: ${value}`));
export class Service {
protected observable<
TObserver extends ServiceObserver,
TArgs extends any[],
TResult extends unknown | Promise<unknown>
>(callback: (observer: TObserver, ...args: TArgs) => TResult) {
return (...args: TArgs) => {
const observer = new ServiceObserver() as NonNullable<TObserver>;
const value = callback(observer, ...args);
return { observer, value };
};
}
}
type ServiceEventCallback<T> = (event: CustomEvent<T>) => void;
export class ServiceObserver<TEvents extends Record<string, any> = Record<string, any>> extends EventTarget {
/**
* General error for not supported methods.
*/
private static NotSupportedError(name: string, replacementName: string) {
return new Error(
`"${ServiceObserver.name}.${name}" is not supported. Please use "${ServiceObserver.name}.${replacementName}".`
);
}
/**
* Typed wrapper for `EventTarget.dispatchEvent`.
*/
public dispatch<T extends keyof TEvents>(type: T, detail: TEvents[T]): boolean {
return super.dispatchEvent(new CustomEvent(type as string, { detail }));
}
/**
* @deprecated - Not supported. Please use `ServiceObserver.dispatch`.
*/
override dispatchEvent(_event: Event): boolean {
throw ServiceObserver.NotSupportedError(this.dispatchEvent.name, this.dispatch.name);
}
/**
* Typed wrapper for `EventTarget.addListener`.
*/
public addListener<T extends keyof TEvents>(
type: T,
callback: ServiceEventCallback<TEvents[T]> | null,
options?: boolean | AddEventListenerOptions | undefined
): this {
super.addEventListener(type as string, callback as EventListener, options);
return this;
}
/**
* @deprecated - Not supported. Please use `ServiceObserver.addListener`.
*/
override addEventListener(
_type: string,
_callback: EventListenerOrEventListenerObject | null,
_options?: boolean | AddEventListenerOptions | undefined
): void {
throw ServiceObserver.NotSupportedError(this.addEventListener.name, this.addListener.name);
}
/**
* Typed wrapper for `EventTarget.removeEventListener`.
*/
public removeListener<T extends keyof TEvents>(
type: T,
callback: ServiceEventCallback<TEvents[T]> | null,
options?: boolean | EventListenerOptions | undefined
): this {
super.removeEventListener(type as string, callback as EventListener, options);
return this;
}
/**
* @deprecated - Not supported. Please use `ServiceObserver.removeListener`.
*/
override removeEventListener(
_type: string,
_callback: EventListenerOrEventListenerObject | null,
_options?: boolean | EventListenerOptions | undefined
): void {
throw ServiceObserver.NotSupportedError(this.removeEventListener.name, this.removeListener.name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment