There is only one sensible way to type an identity function, no surprises here
const identity = <T>(t: T) => t;
But strictly typed identity function is not assignable to arbitrary transform - compiler knows that it returns the same type as it received, so your typing for mapToObject is inconsistent - what is the result type when you call it as
mapToObject<string, number, Date>(new Map<string, number>())
- since it uses the default identity transform, resulting object must hold numbers
- but you explicitly provided third generic parameter, so resulting object must hold
Dates
This needs to be expressed as dependent type - type of resulting object depends on whether the transform argument is given or the default is used. In TypeScript, you can do that with overloading function declarations:
function mapToObject<K, V>(map: Map<K, V>)
: { [n: string]: V };
function mapToObject<K, V, O>(map: Map<K, V>, transformValue: transform<V, O>)
: { [n: string]: O };
function mapToObject<K, V, O>(map: Map<K, V>, transformValue?: transform<V, O>)
: { [n: string]: {} }
{
const transform: (v: V) => {} = transformValue || identity;
return Array.from(map.entries()).reduce((obj, [key, val]) => {
obj[key.toString()] = transform(val) ;
return obj;
}, {});
}
Since actual value type is not used in the implementation at all, it can be given as empty object type {}, which is compatible with both V and O types (you could use union type V | O instead because it's also compatible, but it's more verbose and buys you nothing here)
With these declarations, inconsistent usage is detected by the compiler:
// error: Expected 1-2 arguments, but got 1
mapToObject<string, number, Date>(new Map<string, number>())
mapToObject<string, number>(new Map<string, number>()) // ok
mapToObject<string, number, Date>(new Map<string, number>(), n => new Date(n)) //ok
and the result type is inferred as expected:
const o1 = mapToObject(new Map<string, number>())
// {[n: string]: number}
const o2 = mapToObject(new Map<string, number>(), n => new Date(n))
// {[n: string]: Date}