Last active
January 26, 2021 23:15
-
-
Save gund/79dbb8fc82bfc41a66df46053155c423 to your computer and use it in GitHub Desktop.
Extendable actions service library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Type Utils | |
interface DefaultChecker { | |
__defaultChecker: true; | |
} | |
type Default<T, D> = T | DefaultChecker extends DefaultChecker ? D : T; | |
type MapTo<T, E, M> = T extends E ? M : T; | |
type AsKeyOf<K, T> = K extends keyof T ? K : never; | |
type Observable<T> = {}; | |
interface Type<T> extends AbstractType<T> { | |
new (...args: any[]): T; | |
} | |
interface AbstractType<T> { | |
prototype: T; | |
} | |
interface Generics<T extends any[] = any[]> { | |
__generics: T; | |
} | |
type InferGenerics<T> = T extends Generics<infer G> ? G : never; | |
type InferGeneric<T, I> = MapTo< | |
InferGenerics<T>[AsKeyOf<I, InferGenerics<T>>], | |
undefined, | |
never | |
>; | |
type ExtendGenerics<G extends Generics, T extends any[]> = Omit< | |
G, | |
'__generics' | |
> & | |
Generics<[...G['__generics'], ...T]>; | |
// Implementation | |
type RegistryType<R> = Default<keyof R, string>; | |
type GetFromRegistry<T, R, D = never> = Default<R[AsKeyOf<T, R>], D>; | |
type GetRegistryKey<V, I extends keyof V> = V[I]; | |
type RegistryDeclaration<R> = { [P in keyof R]: Type<R[P]> }; | |
interface ActionsRegistry { | |
// type: ActionHandler; | |
} | |
type ActionType = RegistryType<ActionsRegistry>; | |
type InferAction<T extends ActionType> = GetFromRegistry< | |
T, | |
ActionsRegistry, | |
ActionHandler | |
>; | |
type InferActionContext<T extends ActionType> = InferGeneric<InferAction<T>, 0>; | |
type InferActionReturn<T extends ActionType> = InferGeneric<InferAction<T>, 1>; | |
interface ActionConfig { | |
type: ActionType; | |
// Different types MAY have extra config | |
[k: string]: unknown; | |
} | |
interface ActionHandler<C = unknown, R = unknown> extends Generics<[C, R]> { | |
handleAction(injector: unknown, config: ActionConfig, context: C): Observable<R>; | |
} | |
interface ActionsService { | |
trigger<C extends ActionConfig>( | |
injector: unknown, | |
config: C, | |
context: InferActionContext<C['type']>, | |
): Observable<InferActionReturn<C['type']>>; | |
} | |
interface ActionsModule { | |
withActions(actions: RegistryDeclaration<ActionsRegistry>); | |
} | |
// Project level example | |
interface TableConfig { | |
id: string; | |
} | |
interface TableActionHandler<TC, R = unknown> | |
extends ExtendGenerics<ActionHandler<TableConfig, R>, [TC]> {} | |
type t1 = InferActionContext<'test3'>; | |
type t2 = InferActionReturn<'test3'>; | |
type t3 = InferGeneric<InferAction<'test3'>, 2>; | |
interface ActionsRegistry { | |
test: ActionHandler<boolean, string>; | |
} | |
interface ActionsRegistry { | |
test2: ActionHandler<string, number>; | |
} | |
interface ActionsRegistry { | |
test3: TableActionHandler<'c', 'a'>; | |
} | |
let actionsService: ActionsService; | |
let actionConfig: ActionConfig; | |
actionsService.trigger(null, actionConfig, true); | |
actionsService.trigger(null, { type: 'test' }, true); | |
actionsService.trigger(null, { type: 'test2' }, 'aaa'); | |
actionsService.trigger(null, { type: 'test3' }, { id: '123' }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment