typescript - 根据映射键从接口(interface)映射中选择类型

标签 typescript generics interface typescript-generics

我想编写一个通用的创建方法,该方法生成在 map 内键入的不同对象。问题是 typescript 将所有接口(interface)混合在一起,而不是只在接口(interface)映射中选择一个:

interface A  {
  a: string;
}

interface B {
  b: string;
}

interface ABMap {
  a: A;
  b: B;
}

function create<ID extends keyof ABMap>(id: ID): ABMap[ID] { // this is now combined A & B instead of A | B
  if (id === 'a') {
    return {a: 'a'}; // error a is missing b key 
  } else if (id === 'b') {
    return {b: 'b'};
  }
}

最佳答案

这里有两个问题。
首先,typescript 不会基于类型保护来缩小泛型的定义。这是一种已知和预期的行为,尽管它可能令人沮丧。当您查看 if (id === 'a') , typescript 知道变量 id 的值是 A 类型.然而,它并没有将泛型缩小到仅 A .它对泛型类型完全有效 ID成为联盟A | B和变量 id成为 A .因此,当检查通过时,我们知道 ID必须包含 A ,但我们不知道它是“A 并且只有 A ”。
第二个问题是为什么类型 ABMap[ID]正在缩小到 A & B而不是 A | B .那个我无法解释。
有(至少)三种解决方案。

  • 你可以做你所做的,将返回类型扩大到 ABMap[keyof ABMap]又名 A | B
  • 如果您正在处理一小组配对,例如本例中的两个配对,您可以通过函数重载关联输入和输出:
  • function create(id: 'a'): ABMap['a'] 
    function create(id: 'b'): ABMap['b'] 
    function create(id: keyof ABMap): ABMap[keyof ABMap] {
      if (id === 'a') {
        return {a: 'a'};
      } else {
        return {b: 'b'};
      } 
    }
    
  • 您可以使用 as 保留您的泛型并告诉 typescript 您返回的实际上是正确的类型。关键词。
  • function create<ID extends keyof ABMap>(id: ID): ABMap[ID] {
      if (id === 'a') {
        return {a: 'a'} as ABMap[ID];
      } else {
        return {b: 'b'} as ABMap[ID];
      }
    }
    
    Playground Link

    关于typescript - 根据映射键从接口(interface)映射中选择类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64447785/

    相关文章:

    javascript - Angular 验证一对表单字段为空或都已填充

    java - 在 Java Collections Map<Key,?> 中 "?"指的是什么?

    c++ - 如何在多个类中重用一个接口(interface)实现?

    c# - 不能在派生类的 IEnumerable 基类上使用 LINQ 方法

    javascript - Node Js Transformation JSON by JSON key

    typescript - AngularFire 2 发送密码重置电子邮件

    generics - 错误 : unable to infer enough type information about `_` ; type annotations or generic parameter binding required

    java - 需要传递给我的方法的 'this' 的解释

    javascript - 如何检查 'key' 是否正确填充了 JSON 文件中的 'known' 值

    c# - 直接使用 Linq 表达式变量而不是 lambda 表达式时出错