Last active
October 29, 2020 14:15
-
-
Save yassermzh/c6257f1ed3e94f31303885c89cf5e217 to your computer and use it in GitHub Desktop.
a function that takes data from 3 places
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
// 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