diff --git a/packages/effect-fc/src/Async.ts b/packages/effect-fc/src/Async.ts index af43edf..f35fc17 100644 --- a/packages/effect-fc/src/Async.ts +++ b/packages/effect-fc/src/Async.ts @@ -1,33 +1,30 @@ -/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ -import { Effect, Function, Predicate, Runtime, Scope } from "effect" +/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */ +import { Effect, Predicate, Runtime, Scope } from "effect" import * as React from "react" import * as Component from "./Component.js" -export const TypeId: unique symbol = Symbol.for("@effect-fc/Async/Async") -export type TypeId = typeof TypeId +export const AsyncTypeId: unique symbol = Symbol.for("@effect-fc/Async/Async") +export type AsyncTypeId = typeof AsyncTypeId -export interface Async extends AsyncOptions { - readonly [TypeId]: TypeId +export interface Async extends AsyncPrototype {} +export interface AsyncPrototype { + readonly [AsyncTypeId]: AsyncTypeId } -export interface AsyncOptions { - readonly defaultFallback?: React.ReactNode -} +const PromiseTypeId: unique symbol = Symbol.for("@effect-fc/Async/Promise") -export type AsyncProps = Omit - - -export const AsyncPrototype = Object.freeze({ - [TypeId]: TypeId, +export const AsyncPrototype: AsyncPrototype = Object.freeze({ + [AsyncTypeId]: AsyncTypeId, asFunctionComponent

( this: Component.Component & Async, runtimeRef: React.RefObject>>, ) { - const SuspenseInner = (props: { readonly promise: Promise }) => React.use(props.promise) + const Inner = (props: { readonly [PromiseTypeId]: Promise }) => React.use(props[PromiseTypeId]) + Inner.displayName = `${ this.displayName }Inner` - return ({ fallback, name, ...props }: AsyncProps) => { + return (props: {}) => { const promise = Runtime.runPromise(runtimeRef.current)( Effect.andThen( Component.useScope([], this), @@ -35,49 +32,20 @@ export const AsyncPrototype = Object.freeze({ ) ) - return React.createElement( - React.Suspense, - { fallback: fallback ?? this.defaultFallback, name }, - React.createElement(SuspenseInner, { promise }), - ) + return React.createElement(Inner, { ...props, [PromiseTypeId]: promise }) } }, } as const) -export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, TypeId) +export const isAsync = (u: unknown): u is Async => Predicate.hasProperty(u, AsyncTypeId) export const async = >( self: T -): ( - & Omit> - & Component.Component< - Component.Component.Props & AsyncProps, - Component.Component.Success, - Component.Component.Error, - Component.Component.Context - > - & Async -) => Object.setPrototypeOf( - Object.assign(function() {}, self), +): T & Async => Object.setPrototypeOf( + Object.assign(() => {}, self), Object.freeze(Object.setPrototypeOf( Object.assign({}, AsyncPrototype), Object.getPrototypeOf(self), )), ) - -export const withOptions: { - & Async>( - options: Partial - ): (self: T) => T - & Async>( - self: T, - options: Partial, - ): T -} = Function.dual(2, & Async>( - self: T, - options: Partial, -): T => Object.setPrototypeOf( - Object.assign(function() {}, self, options), - Object.getPrototypeOf(self), -))