我正在try 编写一个函数,该函数接受一个对象数组,并对它们进行映射.该函数有两个可能的签名:

  1. 数据和密钥获取器:

    type KeyMapOnly<T> = (data: T[], keyGetter: (itm: T) => string) => T[]
    
  2. 数据、键获取程序和值获取程序

    type KeyAndValue<T, U> = (
      data: T[],
      keyGetter: (itm: T) => string,
      valueGetter: (itm: T) => U
    ) => Record<string, U>
    

然而,当我试图将这两个放在一起时,我得到了错误.我到底做错了什么?

type KeyGetter<T> = (itm: T) => string                                                                          
type ValueGetter<T, U> = (itm: T) => U                                                                     
                                                                                                                      
const identity = <T>(itm: T): T => itm                                    
                                                                                                         
type IndexFunc = {                                                                                   
  <T>(arr: T[], keyGetter: KeyGetter<T>): Record<string, T>                                              
  <T, U>(                                                                 
    arr: T[],                                                                                                 
    keyGetter: KeyGetter<T>,                                              
    valueGetter: ValueGetter<T, U>                                                                       
  ): Record<string, U>                                                    
}                                                                  
                                                                                     
export const buildIndex: IndexFunc = (                                                            
  arr,                                                                                                    
  keyGetter,                                                                                      
  valueGetter = identity                                                       
) => {                                                                    
  const result = {} as any                                                                                   
                                                                               
  for (const itm of arr) {                                                
    result[keyGetter(itm)] = valueGetter(itm)                                                                  
  }                                                                            
                                                                          
  return result                                                                           
}

使用此配置时,我会收到以下错误:

Parameter 'arr' implicitly has an 'any' type. 
Parameter 'keyGetter' implicitly has an 'any' type.

这两个参数都出现在both个函数重载中,所以我搞不懂它们怎么可能具有类型ANY.

  • data始终是T[]类型
  • keyGetter始终是(itm: T) => string类型

我到底做错了什么?

推荐答案

这被认为是打印脚本的设计限制,如第microsoft/TypeScript#38625条所述.目前函数参数不是contextually typedxoverloaded的函数类型,因此除非您手动将其设置为annotate the parameters,否则它们将被隐式类型化为any,并且您将收到一条警告(假设启用了the --noImplicitAny compiler option).

因此,您的 Select 是手动注释,这需要generic个函数实现:

export const buildIndex: IndexFunc = <T,>(
    arr: T[],
    keyGetter: KeyGetter<T>,
    valueGetter = identity
) => {
    const result = {} as any

    for (const itm of arr) {
        result[keyGetter(itm)] = valueGetter(itm)
    }

    return result
}

或者放弃重载,转而使用某种组合调用签名,例如

type IndexFunc = {
    <T, U = T>(
        arr: T[],
        keyGetter: KeyGetter<T>,
        valueGetter?: ValueGetter<T, U>
    ): Record<string, U>
}

export const buildIndex: IndexFunc = (
    arr,
    keyGetter,
    valueGetter = identity as any // <-- need this
) => {
    const result = {} as any

    for (const itm of arr) {
        result[keyGetter(itm)] = valueGetter(itm)
    }

    return result
}

(请注意,您需要额外的assertion来说服编译器identity是合适的缺省值,因为用户可以,但可能不会执行类似buildIndex<number, boolean>([1, 2, 3], (n) => "k" + n)的操作.)

Playground link to code

Typescript相关问答推荐

TypScript ' NoInfer '类型未按预期工作

在Typescribe中,extends工作,但当指定派生给super时出错""

Angular 行为:属性类型从SignalFunction更改为布尔

不推荐使用Marker类-Google map API警告

如何以Angular 形式显示验证错误消息

如何在另一个参数类型中获取一个参数字段的类型?

PrimeNG日历需要找到覆盖默认Enter键行为的方法

使用2个派生类作为WeakMap的键

在TypeScript中扩展重载方法时出现问题

react 路由不响应参数

TaskListProps[]类型不可分配给TaskListProps类型

设置不允许相同类型的多个参数的线性规则

打字脚本错误:`不扩展[Type]`,而不是直接使用`[Type]`

使用泛型以自引用方式静态键入记录的键

如何避免TS2322;类型any不可分配给类型never;使用索引访问时

如何将元素推入对象中的类型化数组

TypeScript是否不知道其他函数内部的类型判断?

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

TS 条件类型无法识别条件参数

基于泛型的柯里化函数的条件参数