Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- interface BaseConfig<I extends string, T> {
- id: I;
- default: T;
- }
- interface TextConfig<I extends string> extends BaseConfig<I, string> {
- type: "Text";
- }
- interface NumberConfig<I extends string> extends BaseConfig<I, number> {
- type: "Number";
- }
- interface CheckboxConfig<I extends string> extends BaseConfig<I, boolean> {
- type: "Checkbox";
- }
- type Config<I extends string> =
- | TextConfig<I>
- | NumberConfig<I>
- | CheckboxConfig<I>;
- type CompleteConfig<C extends Config<string>> = ReadonlyArray<C>;
- interface StateItem<C extends Config<string>> {
- value: C["default"];
- config: C;
- }
- type State<C extends Config<string>> = {
- [T in C as T["id"]]: StateItem<T>;
- };
- type DeriveStateType<
- I extends string,
- C extends Config<I>
- > = C extends BaseConfig<I, infer T> ? T : never;
- function textConfig<const I extends string>(
- config: Omit<TextConfig<I>, "type">
- ): TextConfig<I> {
- return { type: "Text", ...config };
- }
- function numberConfig<const I extends string>(
- config: Omit<NumberConfig<I>, "type">
- ): NumberConfig<I> {
- return { type: "Number", ...config };
- }
- function checkboxConfig<const I extends string>(
- config: Omit<CheckboxConfig<I>, "type">
- ): CheckboxConfig<I> {
- return { type: "Checkbox", ...config };
- }
- function completeConfig<C extends CompleteConfig<Config<string>>>(
- ...configs: C
- ): C {
- return configs;
- }
- function state<const C extends Config<string>>(
- configs: CompleteConfig<C>
- ): State<C> {
- return configs.reduce(
- (workingState, config) => ({ ...workingState, [config.id]: config }),
- {} as State<C>
- );
- }
- function getStateValue<I extends string, const C extends Config<I>>(
- state: State<C>,
- id: I
- ): DeriveStateType<I, C> {
- // Property 'value' does not exist on type 'State<C>[I]'.
- return state[id].value;
- }
- const myConfigs = completeConfig(
- textConfig({ id: "foo", default: "Hello" }),
- numberConfig({ id: "bar", default: 1337 }),
- checkboxConfig({ id: "baz", default: true })
- );
- const myState = state(myConfigs);
- // I want the below lines to be equivalent but getStateValue is not able to
- // narrow the type down and has type errors.
- // string
- myState["foo"].value;
- // string | number | boolean
- const value = getStateValue(myState, "foo");
Advertisement
Add Comment
Please, Sign In to add comment