代码之家  ›  专栏  ›  技术社区  ›  Will Howell

向字典强制转换接口

  •  3
  • Will Howell  · 技术社区  · 7 年前

    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 保持不变并以某种方式修改 对数 . 有办法做到这一点吗?也许我可以向typescript发出信号,表示不会向其添加新键 numDict 在内部 对数

    Reproduction in TypeScript Playground

    2 回复  |  直到 7 年前
        1
  •  3
  •   Titian Cernicova-Dragomir    7 年前

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

      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);
    
        2
  •  0
  •   Robbie Milejczak Diego Felipe    7 年前

    您只需在此处执行以下操作:

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

    现在呢 StatisticsResult 将使用您定义的索引签名。TypeScript不关心您添加新键,它只关心您将带有索引签名的类型分配给没有索引签名的类型。

    你也可以投 results ,虽然这是更黑客,因为你需要投到 unknown 首先(如果您不这样做,ts会抱怨您的类型没有任何重叠,因为索引符号不一致),这有点违背了目的:

    logNumbers((results as unknown) as NumberDictionary);
    

    StatisticalResult ,您也可以在那里定义索引签名(据我所知,这也违背了 NumberDictionary 无论如何键入:

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