简体   繁体   English

Typescript:从 Map 或 object 获取密钥

[英]Typescript: get keys from Map or object

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 ,它从Map或普通 object 中返回密钥作为普通数组,如下所示:

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:如果我然后尝试从普通的 object 中检索密钥,则可以正常工作:

let a = ((g: string[]) => g)(keys({})) // this works

However, using a Map<number, number> gives me a type error:但是,使用Map<number, number>会给我一个类型错误:

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?我应该如何输入这个以使 TypeScript 编译器理解我的意思?

Update:更新:

Function signature overloading seems to be the way to go here, this version works fine: Function 签名重载似乎是 go 的方式,这个版本工作正常:

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)
}

Check typescript function signature overloading: https://www.typescriptlang.org/docs/handbook/functions.html#overloads检查 typescript function 签名重载: https://www.typescriptlang.org/docs/handbook/functions.html#overloads

you can define a set of different signatures, so you can define a signature for the Map case, and one for the object case:您可以定义一组不同的签名,因此您可以为object案例定义一个签名,为Map案例定义一个签名:

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)
}

You can use plain functions with generics:您可以将普通函数与 generics 一起使用:

function keys<K extends PropertyKey>(m: Map<K, any> | { [P in K]: any }): K[] {
    if (m instanceof Map) return Array.from(m.keys())
    return Object.keys(m) as K[]
}

let a = (g => g)(keys({})) // never[]
let a0 = (g => g)(keys({foo: "bar"})) // "foo"[]
let a1 = (g => g)(keys(new Map<number, number>())) // number[]
let a2 = (g => g)(keys<number>(new Map<number, number>())) // number[]
let a3 = (g => g)(keys(new Map<1 | 2, number>())) // (1 | 2)[]

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM