I'm struggling to come up with the correct typing for a function that creates an object with setter and getter properties. I believe using template string literals might be the way to go, but I'm having trouble figuring out the right combination of types. In pseudo-code JS, I envision something like this:
function createGetterAndSetter( key ) {
return {
[`get${capitalize(key)}`] : ( model ) => {
return model[key]
},
[`set${capitalize(key)}`] : ( model, value ) => {
return {
...model,
[key] : value
}
}
}
}
This is what I have attempted so far:
interface Model {
[key:string]: any
}
type ModelKey = keyof Model & string
type Setter = ( model : Model, value : unknown ) => Model
type Getter = ( model : Model ) => unknown
type GetterKey<T extends string> = `get${Capitalize<T>}`
type SetterKey<T extends string> = `set${Capitalize<T>}`
type GetterSetterKeys<T extends string> = GetterKey<T> | SetterKey<T>
type GetterSetter<T extends GetterKey | SetterKey> = Record<GetterSetterKeys<T>, Getter | Setter>
function createGetterAndSetter<T extends ModelKey>( key : ModelKey ) : GetterSetter<T> {
const keyName = `${key[0].toUpperCase() + key.substring( 1 )}`
return {
[`set${keyName}`] : createSetValue( key, setOpts ) as Setter,
[`get${keyName}`] : createGetValue( key, getOpts ) as Getter
} as GetterSetter<T>
}
I'm relatively new to TypeScript, so there are probably mistakes in my approach, but it does seem to make the compiler aware that the output of createGetterAndSetter
consists of getX and setX keys. However, it struggles to differentiate whether the values for those keys are getters or setters - only recognizing them as part of a union.
It may be worth noting that I drew inspiration from the createApi
function in redux-toolkit, which has the ability to generate named hooks based on specified endpoints.