@expressive/react
Version:
Use classes to define state in React!
106 lines (100 loc) • 4.35 kB
TypeScript
import { Context } from '@expressive/mvc';
import React__default, { FunctionComponent } from 'react';
declare module '@expressive/mvc' {
namespace Model {
interface Component<T extends Model, P extends Model.Assign<T>> extends FunctionComponent<P & Model.Props<T>> {
displayName?: string;
Model: Model.Type<T>;
}
function as<T extends Model, P extends Model.Assign<T>>(this: Model.Init<T>, render: (props: P, self: T) => React__default.ReactNode): Component<T, P>;
}
}
declare module '@expressive/mvc' {
namespace Model {
function use<T extends Model>(this: Model.Init<T>, apply?: Model.Assign<T>, repeat?: boolean): T;
function use<T extends Model>(this: Model.Init<T>, callback?: Model.Callback<T>, repeat?: boolean): T;
}
}
/** Type may not be undefined - instead will be null. */
type NoVoid<T> = T extends undefined | void ? null : T;
type ForceRefresh = {
/** Request a refresh for current component. */
(): void;
/**
* Request a refresh and again after promise either resolves or rejects.
*
* @param waitFor Promise to wait for.
* @returns Promise which resolves, after refresh, to same value as `waitFor`.
*/
<T = void>(waitFor: Promise<T>): Promise<T>;
/**
* Request refresh before and after async function.
* A refresh will occur both before and after the given function.
*
* **Note:** Any actions performed before first `await` will occur prior to refresh.
*
* @param invoke Async function to invoke.
* @returns Promise which resolves returned value after refresh.
*/
<T = void>(invoke: () => Promise<T>): Promise<T>;
};
declare module '@expressive/mvc' {
namespace Model {
type GetFactory<T extends Model, R> = (this: T, current: T, refresh: ForceRefresh) => R;
type GetEffect<T extends Model> = (this: T, current: T, refresh: ForceRefresh) => null;
/** Fetch instance of this class from context. */
function get<T extends Model>(this: Model.Type<T>): T;
/** Fetch instance of this class optionally. */
function get<T extends Model>(this: Model.Type<T>, required: false): T | undefined;
/** Fetch instance of this class from context. */
function get<T extends Model>(this: Model.Type<T>, requireValues: true): Required<T>;
function get<T extends Model, R>(this: Model.Type<T>, factory: GetFactory<T, Promise<R> | R>): NoVoid<R>;
function get<T extends Model>(this: Model.Type<T>, factory: GetEffect<T>): null;
}
}
declare module '@expressive/mvc' {
namespace Model {
type HasProps<T extends Model> = {
[K in Exclude<keyof T, keyof Model>]?: T[K];
};
/**
* Props which will not conflict with a Model's use as a Component.
*
* Built-in properties must be optional, as they will always be omitted.
*/
type RenderProps<T extends Model> = HasProps<T> & {
is?: undefined;
get?: undefined;
set?: undefined;
};
/** Model which is not incompatable as Component in React. */
interface Compat extends Model {
render?(props: RenderProps<this>, self: this): React.ReactNode;
fallback?: React.ReactNode;
}
interface BaseProps<T extends Model> {
/**
* Callback for newly created instance. Only called once.
* @returns Callback to run when instance is destroyed.
*/
is?: (instance: T) => void;
render?(props: HasProps<T>, self: T): React.ReactNode;
/**
* A fallback react tree to show when suspended.
* If not provided, `fallback` property of the Model will be used.
*/
fallback?: React.ReactNode;
}
type Props<T extends Model> = T extends {
render(props: infer P, self: any): any;
} ? BaseProps<T> & HasProps<T> & Omit<P, keyof Model> : BaseProps<T> & HasProps<T> & {
children?: React.ReactNode;
};
}
}
declare const Pragma: {
useContext(): Context;
useFactory<T extends Function>(factory: (refresh: () => void) => T): T;
useLifecycle(callback: () => () => void): void;
};
export { Pragma };