将函数字符串名称传递给函数,tsc抛出错误

时间:2017-06-30 05:30:59

标签: typescript

我想将函数字符串名称传递给函数, 所以我可以这样使用它:

function processArrayObjectPropName<T extends IkeyOfObject>(items: T[], methodName: string = 'toLowerCase'): T[] {
  for (const item of items) {
    const keys: string[] = Object.keys(item);
    let keyCount: number = keys.length;
    while (keyCount--) {
      const key: string = keys[keyCount];
      item[key[methodName]()] = item[key];  //throw an error
    }
  }

  return items;
}

但是,tsc给了我这个错误:

Error:(38, 16) TS7015:Element implicitly has an 'any' type because index expression is not of type 'number'.

2 个答案:

答案 0 :(得分:1)

key是一个字符串,methodName也是一个字符串,表达式key[methodName]将使用一个字符串来索引另一个字符串,这就是您收到错误的原因。

我无法弄清楚你想要实现的目标。将对象的所有键复制到这些键的小写(或其他错位)版本?那可能是:

  item[(key as any)[methodName]()] = item[key];

key转换为any类型允许您下标字符串,从而间接获取其方法。

答案 1 :(得分:1)

TL; DR:使用标有Solution的代码段。

错误消息有意义,因为当您尝试运行key[methodName]时,它实际上会调用String.prototype.operator[],签名为readonly [index: number]: string;

由于methodName这里是string而不是number,因此会根据其签名提供警告信息。

我们在这里可以做的是使methodName更具体,因此TypeScript知道key[methodName]在任何情况下都不会返回null

function processArrayObjectPropName<T extends IkeyOfObject>
    (items: T[], methodName: keyof String = 'toLowerCase'): T[] {

现在,TypeScript会发出另一个警告,因为不同函数的参数数量可能不同。

[ts] Cannot invoke an expression whose type lacks a call signature. Type 'number | (() => string) | ((pos: number) => string) | ((index: number) => number) | ((...strings:...' has no compatible call signatures.

因此我们需要使methodName的类型规范更加具体,确保它只包含函数接受0参数;

通过这种方式,我们会有类似的东西,编译:

// Solution 1
type StringMethodWithZeroParameter = 'toLowerCase' | 'toUpperCase'

function processArrayObjectPropName<T extends IkeyOfObject>
    (items: T[], methodName: StringMethodWithZeroParameter = 'toLowerCase'): T[] {

同时,如果可以更改签名,则可以使用lambda而不是函数名称进行传递。

// Solution 2
processArrayObjectPropName(items, String.prototype.toLowerCase);

function processArrayObjectPropName<T extends IkeyOfObject>(items: T[], transformer: (i: string) => string): T[] {
    for (const item of items) {
        const keys: string[] = Object.keys(item);
        let keyCount: number = keys.length;
        while (keyCount--) {
            const key: string = keys[keyCount];
            item[transformer(key)] = item[key]; 
        }
    }
    return items;
}