如何在 TypeScript 中添加索引签名

Posted

技术标签:

【中文标题】如何在 TypeScript 中添加索引签名【英文标题】:How to add index signature in TypeScript 【发布时间】:2018-07-24 04:32:39 【问题描述】:

我正在尝试使用带有 Typescript 的 reduce 来达到传入消息的总数。我对如何添加索引签名感到困惑。我不断收到错误消息:“元素隐式具有 'any' 类型,因为类型 '' 没有索引签名。”在变量 newArray 和 counts[k] 上。我已经阅读了几个类似的问题,但还没有弄清楚如何将它们应用于我的特定场景。我是 javascript 和 TypeScript 的新手。

这是我的数组:

        var data = [
         time: '9:54' , 
         time: '9:54' ,
         time: '9:54' ,
         time: '9:55' , 
         time: '9:55' ,
         time: '9:55' ,
         time: '9:55' ,
         time: '9:56' , 
         time: '9:56' ,
         time: '9:56' ,
         time: '9:56' ,
         time: '9:57' , 
         time: '9:57' ,
         time: '9:57' ,
         time: '9:57' ,
         time: '9:57' 
    ];

这就是我需要我的数组在图表图中使用的方式:

        var dataWithCounts = [
         time: '9:54', messages: 3 , 
         time: '9:55', messages: 4 , 
         time: '9:56', messages: 4 , 
         time: '9:57', messages: 5 
    ];

借助来自 Stack Overflow 问题的“只是一个学生”的回答:Group and count values in an array ,我有以下内容。

        var counts = data.reduce((newArray, item) => 
           let time = item.time;
           if (!newArray.hasOwnProperty(time)) 
               newArray[time] = 0;
            
           newArray[time]++;
           return newArray;
        , );

        console.log(counts);

        var countsExtended = Object.keys(counts).map(k => 
           return  time: k, messages: counts[k] ;
       );

       console.log(countsExtended);

在哪里以及如何声明索引签名?以下是我尝试过的各种方法。

let newArray: [time: string] ; 并收到重复标识符错误。

将字符串添加到参数var counts = data.reduce((newA:string, item) 给我一个错误“元素隐式具有'any'类型,因为索引表达式不是'number'类型。”

添加newA[time].toString()给我错误,“赋值表达式的左侧必须是变量或属性访问。”

【问题讨论】:

不是打字员,但会猜测这是因为您没有向reduce 回调声明第三和第四个参数。传递给reduce 的函数得到 1。累加器。 2. 数组中的当前项。 3.当前指数。 4.原始数组。 在您的 tsconfig.json 文件中将 noImplicitAny 设置为 false。 【参考方案1】:

原始问题的答案

主要的警告是reduce 累加器值没有正确输入。

原码:

const result = data.reduce(someLogicCallback, )

需要通过以下方式进行:

const accumulator: [key: string]: number = 
const result = data.reduce(someLogicCallback, accumulator)

其他可能的注意事项

这部分可能对后来偶尔的谷歌人有所帮助。

我来这里是为了解决类似的问题,但在我的情况下,我有一个对象已经预定义了类型

typeof someObject // predefinedType

type predefinedType = 
  someKey: number;
  otherKey: number;

当我尝试从该对象中提取条目时出现index signature is missing in type predefinedType 错误

const entries = Object.entries<number>(someObject);

显而易见的解决方案是进行类型断言

type TypedIndexObj = [key: string]: number
const entries = Object.entries<number>(someObject as TypedIndexObj);

但这太严格了,因为它总是将someObject 的值类型断言为number,这可能会随着时间而改变。

我想出的添加此类对象的索引类型的最佳方法是使用keyof语法

type TypedIndexObj = [key in keyof typeof someObject]:(typeof someObject)[key]
const entries = Object.entries<number>(someObject as TypedIndexObj);

参考:原始问题的更正代码

这是原始问题中代码的完全键入的更正版本:

const accumulator: [key: string]: number = 

const counts = data.reduce((_accumulator, item) => 
  const time = item.time;
  // no error on the next line
  if (!_accumulator.hasOwnProperty(time)) 
      _accumulator[time] = 0;
   
  _accumulator[time]++;
  return _accumulator;
, accumulator);

const countsExtended = Object.keys(counts).map(k => 
    return  time: k, messages: counts[k] ;
);

【讨论】:

【参考方案2】:

您必须添加具有索引签名的类型。例如。

const myObj: [key: string]: string = 
  someProperty: 'someValue',
;

[key: string]: any 告诉 Typescript 这个 obj 有一个字符串类型的索引签名。

【讨论】:

【参考方案3】:

您的数组的正确类型是:

Array<time: string>

或:

time: string[]

或:

[key: number]: time: string

【讨论】:

【参考方案4】:

.reduce 调用中的累加器类型几乎肯定是问题所在。因为它只是作为 给出的,所以它的类型就是这样推断的,而 类型没有索引签名。您可以通过强制转换初始值来解决此问题,以便它包含签名:

var counts = data.reduce((newArray, item) => 
    let time = item.time;
    if (!newArray.hasOwnProperty(time)) 
        newArray[time] = 0;
     
    newArray[time]++;
    return newArray;
,  as [key: string]: any); // <-- note the cast here

我提供了索引签名类型any,但您可能希望针对您的特定情况使其更具体。

【讨论】:

谢谢Crice!完美运行【参考方案5】:

如果我理解你,你需要为对象创建接口...

interface counts_t
    time?: string,
    messages?: number


var data: counts_t[] = [
     time: '9:54' , 
     time: '9:55' , 
     time: '9:56' , 
     time: '9:57' 
];

    var counts = data.reduce((newArray:counts_t, item:counts_t) => 
       let time = item.time;
       if (!newArray.hasOwnProperty(time)) 
           newArray[time] = 0;
        
       newArray[time]++;
       return newArray;
    , );

    console.log(counts);

    var countsExtended: counts_t[] = Object.keys(counts).map(k => 
       return  time: k, messages: counts[k] ;
    );

   console.log(countsExtended);

【讨论】:

谢谢'我曾经和一只熊搏斗'。这可能是另一种解决方法。 Crice 上面的回答奏效了。很棒的用户名顺便说一句

以上是关于如何在 TypeScript 中添加索引签名的主要内容,如果未能解决你的问题,请参考以下文章

如何创建具有索引签名和不同类型的固定属性的 TypeScript 接口?

Typescript - 具有通用类型函数的索引签名

在 TypeScript 中禁止可索引类型

如何为映射类型添加索引签名?

Type 中缺少索引签名 - AngularJS + TypeScript 验证使用 $validators

在“”类型上找不到带有“数字”类型参数的索引签名 - Typescript 编译器错误