First of all, I feel like I'm on the wrong path to begin with.
I have the following code:
export const fastMap = {};
export type FastMapOptions<S, T> = {
key: string;
value: T;
selector: (state: RootState) => T;
dispatch: (state: S, action: PayloadAction<any>) => void;
};
export const addToFastMap = <S, T>(options: FastMapOptions<S, T>) => {
const { key, value, selector, dispatch } = options;
fastMap[key] = {
value,
selector,
atom: atom({ key, default: value }),
dispatch
};
};
As you can see, fastMap
isn't really anything. However, my options
(value, selector, atom, dispatch
) are clearly typed. Unfortunately, I can't seem to get fastMap
to play nice. If I were to do:
addToFastMap<SliceState, number>({
key: "margin",
value: 20,
selector: (state: RootState) => state.properties.margin,
dispatch: marginUpdatedReducer
});
And then simply access fastMap['margin']
, it will not be able to tell me anything about what's in there, however, it's clear that the value
is a number
, the key
is a string
and so on.
Naturally, I'm using generics, as I need them here to be able to correctly type these arguments.
Is there any way to get the correct typings in this case?
CodePudding user response:
So you can achieve the desired behaviour by using a building pattern like this.
export type FastMapOptions<S, T> = {
value: T;
selector: (state: S) => T;
dispatch: (state: S, action: PayloadAction<any>) => void;
};
function fastMapBuilder<T extends Record<string, any>>(inital: T) {
const fastMap = inital
const self = {
fastMap,
add<K extends string, State, Return>(key: K, options: FastMapOptions<State, Return>) {
const next: T & { [Key in K]: { key: Key } & FastMapOptions<State, Return> } = { ...inital, [key]: { ...options, key } }
return fastMapBuilder(next)
},
build() {
return fastMap
}
}
return self
}
const fastMap = fastMapBuilder({})
.add("hover", { value: "idk", selector: (s: string) => "", dispatch: (s, a: {}) => { } })
.add("over", { value: 0, selector: (s: string) => 0, dispatch: (s, a: {}) => { } }).build()
//{
// hover: {
// key: "hover";
// } & FastMapOptions<string, string>;
//} & {
// over: {
// key: "over";
// } & FastMapOptions<string, number>;
//}