Let's say I want to write a function that returns the keys from either a Map or a plain object as a plain array, something like this:
function keys <K>(m: Map<K, any> | { [key: string]: any }) {
if (m instanceof Map) return Array.from(m.keys())
return Object.keys(m)
}
If I then try to retrieve the keys from a normal object, that works fine:
let a = ((g: string[]) => g)(keys({})) // this works
However, using a Map<number, number> gives me a type error:
let a = ((g: number[]) => g)(keys(new Map<number, number>()))
// Argument of type 'number[] | string[]' is not assignable to parameter of type 'number[]'
let a = ((g: number[]) => g)(keys<number>(new Map<number, number>()))
// Even this produces the same error
let a = ((g: number[]) => g)(keys(new Map<number, number>()) as number[])
// This works but the cast kind of defeats the purpose
What am I missing? How should I type this to make the TypeScript compiler understand what I mean?
Update:
Function signature overloading seems to be the way to go here, this version works fine:
function keys <K>(m: Map<K, any>): K[]
function keys (m: { [key: string]: any }): string[]
function keys (m: any): any {
if (m instanceof Map) return Array.from(m.keys())
return Object.keys(m)
}