Skip to content

Instantly share code, notes, and snippets.

@yassermzh
Last active October 29, 2020 14:15
Show Gist options
  • Save yassermzh/c6257f1ed3e94f31303885c89cf5e217 to your computer and use it in GitHub Desktop.
Save yassermzh/c6257f1ed3e94f31303885c89cf5e217 to your computer and use it in GitHub Desktop.
a function that takes data from 3 places
// as a note for myself! for me only `public gist` is possible. sorry if you end up here.
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
type JsonMap = Record<string, any>
type State = { a: number };
function getState(): State {
return { a: 1 };
}
// a function that requires data from 3 places:
// - from external place: state
// - from params (not changing, fixed shape) like { name: string }
// - as argument (changing) like { fieldId: number }
// it we wanted to provide all of them each time and together:
// f(state, params, argument) { return ... }
// but we already know the params but not the argument, while the state is changing out of our control.
const f = (params: { name: string }) => (args: any) => {
const state = getState();
// now we have all of them.
};
const f0 = f({ name: 'p1' });
f0({ fieldId: 1 });
// but how to type args? args type is a function of params
// so if params.name == 'p1', then we expect {fieldId: number} as argument
// one way is to create different functions for different values of params
const f1 = (args: { fieldId: number }) => {
const params = { name: 'p1' };
const state = getState();
const data = { params, args, state };
// extra steps similar for all params
};
// but how to avoid duplicate in getState and extra steps for fi's?
const extraSteps = (data: any) => {};
const f2 = (args: { fieldId: number }) => {
const params = { name: 'p1' };
const state = getState();
const data = { params, args, state };
extraSteps(data);
};
// let's try another way: create fi's by calling a function.
// not same as above. for example, can't have the case that fj won't require state.
const creator = (params: { name: string }, getData: (args: any, state: State) => JsonMap) => (args: any) => {
const state = getState();
const data = getData(args, state);
// extra steps
};
const f3 = creator({ name: 'p1' }, (args: { fieldId: number }, state: State) => {
const data = { args, state };
return data;
});
// one problem: can have multiple functions with same params.name. let's forget that.
// but how to type getData
const creator1 = <T>(params: { name: string }, getData: (args: T, state: State) => JsonMap) => (args: T) => {
const state = getState();
const data = getData(args, state);
// extra steps
};
const f4 = creator1({ name: 'p1' }, (args: { fieldId: number }, state: State) => {
const data = { args, state };
return data;
});
// @ts-expect-error not matching
f4(1);
f4({ fieldId: 1 });
// @ts-expect-error extra argument passed
f4({ fieldId: 1, x: 1 });
// so what about the case no argument is required. just state.
const f5 = creator1({ name: 'p1' }, (args: never, state: State) => {
const data = { state };
return data;
});
// @ts-expect-error expects still one arguments
f5();
// currently creator requires (args: T). it's not optional. can't have no arguments case.
const creator2 = <T>(params: { name: string }, getData: (state: State, args?: T) => JsonMap) => (args?: T) => {
const state = getState();
const data = getData(state, args);
// extra steps
};
const f6 = creator2({ name: 'p1' }, (state: State) => {
const data = { state };
return data;
});
f6();
// should fail here, but won't!
// f6: (args?: unknown) => void
f6(1);
// how to fix this?
// one possible way is to have different creator functions: creatorWithNoArgs and creatorWithArgs
const creatorWithArgs = creator2;
const creatorWithNoArgs = <T>(params: { name: string }, getData: (state: State) => JsonMap) => () => {
const state = getState();
const data = getData(state);
// extra steps
};
const f7 = creatorWithNoArgs({ name: 'p1' }, (state: State) => {
const data = { state };
return data;
});
f7();
// @ts-expect-error not accepting argument
f7(1);
// works. but can we not do this? can we instead overload functions?
function creator3(params: { name: string }, getData: (state: State) => JsonMap): () => void;
function creator3<T>(params: { name: string }, getData: (state: State, args: T) => JsonMap): (args: T) => void;
function creator3(params: any, getData: any) {
function helper(args?: any) {
const state = getState();
}
return helper;
}
const f8 = creator3({ name: 'p1' }, (state) => ({ id: state.a }));
f8();
// @ts-expect-error not accepting argument
f8(1);
const f9 = creator3({ name: 'p1' }, (state: State, args: { x: number }) => ({ id: state.a, x: args.x }));
f9({ x: 1 });
// @ts-expect-error missing argument
f9();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment