将接口投射到字典

时间:2019-01-17 15:55:30

标签: typescript casting

我有一个函数logNumbers,它接受​​一个字典,其中所有键都是字符串,所有值都是数字。我想用对象属于更严格的接口来调用logNumbers,但仍然满足那些条件。

interface NumberDictionary {
  [key: string]: number;
}

interface StatisticsResult {
  mean: number;
  mode: number;
  median: number;
}

function logNumbers(numDict: NumberDictionary) { ... }

const results: StatisticsResult = {
  mean: 1,
  mode: 2,
  median: 2,
};

// 
// Error:
//   Argument of type 'StatisticsResult' is not assignable to parameter of type 'NumberDictionary'.
//   Index signature is missing in type 'StatisticsResult'.
//
logNumbers(results);

我希望StatisticsResult保持不变,并以某种方式修改logNumbers的签名。有没有办法做到这一点?也许我可以向打字稿发信号说,numDict内不会向logNumbers添加任何新键?

Reproduction in TypeScript Playground

2 个答案:

答案 0 :(得分:3)

如果您的目标是将函数限制为仅具有数字属性的对象,则可以将通用类型参数限制为仅具有数字的记录。

  interface StatisticsResult {
    mean: number;
    mode: number;
    median: number;
  }

  function logNumbers<T extends Record<keyof T, number>>(num: T) {
    // Log the numbers as a table or something
  }

  const results: StatisticsResult = {
    mean: 1,
    mode: 2,
    median: 2,
  };

  //ok
  logNumbers(results);

答案 1 :(得分:0)

您在这里要做的只是:

interface StatisticsResult extends NumberDictionary {
  mean: number;
  mode: number;
  median: number;
}

,现在StatisticsResult将使用您定义的索引签名。 TypeScript不在乎您添加新键,而只是在乎您要将具有索引签名的类型分配给没有索引的类型。

您也可以强制转换为results,尽管这样做比较棘手,因为您需要首先强制转换为unknown(如果不强制转换,ts会抱怨您的类型没有任何重叠由于索引的标志性差异)和失败的目的:

logNumbers((results as unknown) as NumberDictionary);

最后,尽管您说过您不想更改StatisticalResult,但您也可以在其中定义索引签名(据我所知,这样做也违背了使用NumberDictionary类型的目的:< / p>

interface StatisticsResult{
  [key: string]: number;
  mean: number;
  mode: number;
  median: number;
}