typescript - 在字典属性中推断通用类型

标签 typescript

我有一个通用接口(interface),其中我希望一个属性只包含来自另一个属性的键,并且具有相同的类型....

interface IMyInterface<T> {
    propA: T;
    propB: { [key in keyof T]?: T[key] };
}

这很好,我以前做过很多次类似的事情......基本上我希望它根据我传递给 propA 的内容推断 T 是什么。

但是这是我的问题,我有一本包含许多 IMyInterface 类型的字典....

interface IMyDictionary {
    [key: string]: IMyInterface;
}

这就是我的问题所在,上面的定义需要一个泛型类型....但是我使用的任何类型都将应用于每个属性。如果我使用 any 而不是它会破坏这一点,因为在声明我的字典时它假定一切都是 any。

interface IInterfaceA {
    name: string;
    age: number;
}

const objA: IInterfaceA = {
    name: 'John',
    age: 18
}

const myDictionary: IMyDictionary {
    test1: {
        propA: objA,
        propB: { age: 40 }
    }
}

所以基本上,当将值分配给上面的 myDictionary 时,我希望它推断 propA 是 IInterfaceA 类型,并且在 propB 中只允许属性名称为字符串类型和年龄为数字类型。

我可以通过不定义 IMyDictionary 类型,一个一个地创建每个项目,然后将它们分配给一个新对象 (myDictionary) 来轻松地做到这一点......

const test1: IMyInterface = {
    propA: objA,
    propB: { age: 40 }
}

const myDictionary = { test1 }

这会推断出 test1 的通用类型,然后推断出 myDictionary 的类型,使用准确的属性名称,而不是字符串数组。但如果可能的话,我宁愿使用普通的旧对象赋值语法。

我想不出一种方法来声明 IMyDictionary 的类型以强制它为 IMyInterface 的每个实例推断通用类型。或者,我对定义 IMyInterface 以推断 propB 的属性和类型的不同方法的想法持开放态度。

提前致谢!

最佳答案

您要查找的类型是字典,其中每个条目都是一些 IMyInterface<T>类型,但不是任何特定 T .这可能最好表示为 existential type喜欢(可能){[k: string]: IMyInterface<exists T>} ,目前在 TypeScript 中不受本地支持(大多数其他具有泛型的语言也不支持)。 TypeScript(以及大多数其他具有泛型的语言)只有通用类型:想要类型值的人 X<T>可以为 T 指定任何类型他们想要的,并且值(value)的提供者必须能够遵守。存在类型则相反:想要提供类型值的人 X<exists T>可以为 T 选择任何特定类型他们想要的,并且该值的接收者只需要遵守。存在类型让您可以将泛型类型“隐藏”在非泛型类型中。

但是,TypeScript 没有存在类型,所以我们必须做些别的事情。 (好吧,它没有原生存在类型。您可以通过使用通用函数和通过回调反转控制来 emulate them,但这比我要建议的解决方案更复杂接下来。如果你仍然对存在主义感兴趣,你可以阅读关于它的链接文章)


我们能做的下一个最好的事情是描述 IMyDictionary 的形状作为泛型类型,我们并不真正关心它,并让编译器尽可能地为我们推断它。这是一种方法:

type IMyDictionary<T> = { [K in keyof T]: IMyInterface<T[K]> }
const asIMyDictionary = <T>(d: IMyDictionary<T>) => d;

这个想法是,而不是将变量声明为 IMyDictionary 类型, 你使用辅助函数 asIMyDictionary()取值并生成合适的类型 IMyDictionary<T> .顺便说一句,这只有效,因为类型 IMyDictionary<T>homomorphic mapped type , 所以 T可以从 IMyDictionary<T> 类型的值中推断出来.让我们看看它的实际效果:

const myDictionary = asIMyDictionary({
  test1: {
    propA: { name: "John", age: 18 },
    propB: { age: 40 }
  },
  test2: {
    propA: { size: 10, color: "blue" },
    propB: { color: "purple" }
  },
  test3: {
    propA: { problem: true },
    propB: { oops: false } // error!
    //       ~~~~~~~~~~~~
    // 'oops' does not exist in type '{ problem?: boolean | undefined; }'
  }
});

这有效,并在您预期的地方出现错误。耶!

这里的警告是你仍然需要绕过这个 T你不关心的类型。您希望只处理具体的 IMyDictionary 的任何函数或类型将不得不变得通用。也许这对你来说并不太痛苦。如果是,您可以考虑“模拟”存在类型。但我已经在这里写了很多,所以希望上面的内容能帮助你......如果你需要我写出模拟的存在版本,我可以。

祝你好运!

关于typescript - 在字典属性中推断通用类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56079590/

相关文章:

javascript - 在同一个 React 应用程序中使用 .tsx 和 .js 文件是一个不好的约定吗?

typescript - 从联合类型中提取,其中鉴别器也是联合

import - 忽略 typescript 上的 "cannot find module"错误

javascript - 获取元素指令的html结构(或模板)

reactjs - 如何解决 Typescript 错误——mapbox-gl 和 React hooks

angular - 获取组件中动态模板的内容

typescript - 为什么私有(private)属性是接口(interface)的一部分?

angular - 使用 Angular Renderer2 在 svg rect 上添加 onclick 事件

typescript - 是否可以避免 Typescript 上的长相对导入路径?

javascript - 字符串原型(prototype)在浏览器中有效,但在 Node 中无效