This is a function that finds and returns a value by key in the map, or returns a defaultValue if not found.
import { Map } from "immutable";
import { curry } from "ramda";
export const nullishGet = curry(
<V>(defaultValue: V, key: string, map: Map<string, V>): V =>
map.get(key) ?? defaultValue
);
And I added a function to set the defaultValue to []
when the value I'm looking for is an array.
export const nullishGetArray = nullishGet<unknown[]>([]);
the type I expected:
Curry<(key: string, map: Map<string, unknown[]>) => unknown[]>
But it was
Curry<(defaultValue: unknown, key: string, map: Map<string, unknown>) => unknown>
I also wrote a version that doesn't specify the generic type. like this
export const nullishGetArray = nullishGet([])
//the type of nullishGetArray is Curry<(key: string, map: Map<string, unknown>) => unknown>
Simply put, it seems that the generic is not properly applied when trying to use it together with curry.
Is this because Ramda is not friendly with TypeScript, or am I doing something wrong?
If I were to write what I actually want without using curry, it would look like the following.
export const nullishGet = <V>(
key: string | number,
map: Map<string | number, V>,
defaultValue: V
): V => {
return map.get(key) ?? defaultValue
}
export const nullishGetArray = <V>(
key: string | number,
map: Map<string | number, V[]>,
defaultValue: V[] = []
): V[] => nullishGet<V[]>(key, map, defaultValue)
It's a bit awkward, but you can achieve what you're trying to do by moving the around a few things:
import Immutable from "immutable";
import * as R from "ramda";
// Define implementation outside of Ramda's curry
function nullishGetBase<V>(
defaultValue: V,
key: string,
map: Immutable.Map<string, V>
): V {
return map.get(key) ?? defaultValue;
}
// Note the explicit type here
const nullishGetArray = R.curry(nullishGetBase<unknown[]>)([]);
// result type is unknown[]
const result = nullishGetArray("foo", Immutable.Map({ foo: ["bar"] }));
I think it's failing with your version because the generic parameter V
does not have any constraints, and it will default/fallback to unknown
. In turn, that will override any other type you throw at it.