如何从键而不是值推断类型参数?

2023-12-27

我有一个表示有向图结构的类,它是具有一个类型参数的通用类K extends string对于节点名称。图表是通过传递一个对象来构造的,例如{a: ['b'], b: []}在这个最小的例子中代表两个节点a and b,有一条边a → b.

class Digraph<K extends string> {
    constructor(readonly adjacencyList: Record<K, K[]>) {}

    getNeighbours(k: K): K[] {
        return this.adjacencyList[k];
    }
}

然而,像这样声明,类型参数K是从数组的内容推断的,而不是从对象的属性名称推断的。这意味着K变成'b'代替'a' | 'b',所以 Typescript 会给出错误,因为它认为a是对象字面量中的多余属性。

// inferred as Digraph<'b'> instead of Digraph<'a' | 'b'>
// error: Argument of type '{ a: string[]; b: never[]; }' is not assignable to parameter of type 'Record<"b", "b"[]>'.
let digraph = new Digraph({
    a: ['b'],
    b: [],
});

有没有办法拥有K直接从属性名称而不是它们的值推断出来?

游乐场链接 https://www.typescriptlang.org/play?#code/MYGwhgzhAEAiCWBzATmADgCwDwGloFMAPAF3wDsATGCY5eMxAPmgG8AoaT6YAezJuQBXYMR7IAFMnxgKfEAE9oMgFZhg5YPIAy8GgC5oAJXy9kFXABpoOANoBdRgEpWAXzYcuifMQBy+JBgARjyCyBDiANYGOI7R9qweXFxSxKFk0MQYugB0Kmoa2rrENhF2ANyJ0G5ubAD0tdD0AGb4yFIUSjAIKOjYAOSBfcz0NNIdPE1wSKiYWH1gfdAAPtADQ3UNrchiBgCCyIiCALbkxNATGfJo+KssSgYC9Ij2ZdCBBmT4AG6tL1WLumgZB4Z0gECQZDAgRAN1E0DQYFQJ1IyHOk2IVxufWMpnMACJAnirAS8fZGH1smwYWcKNNetAALxA-AAdymPUw4nYSTABhsazsFkq72g9iFLkcFSAA


我尝试的一个解决方案是添加另一个类型参数T extends Record<K, K[]>并声明constructor(readonly adjacencyList: T) {}。然后多余的财产错误就消失了,但是现在K仅推断为string.

另外,类型Digraph<K, T>太具体了 - 具有相同节点的两个有向图应该可以彼此分配,即使它们具有不同的边,而且我宁愿不必写Digraph<K, Record<K, K[]>> or Digraph<K, any>来解决这个问题。我正在寻找一种不添加额外类型参数或更改内容的解决方案K如果可能的话,将会是。


所以你的问题是有多个候选推理站点K在类型中Record<K, K[]>,并且编译器的推理算法优先考虑错误的算法。您希望能够告诉编译器它不应该使用第二个K(在属性值位置的数组元素中)进行推断,并且应该只使用第一个K(在属性关键位置)用于此目的。它应该只关注之后的第二个站点K被推断,并且仅check推断的类型有效。


有一个未决问题位于微软/TypeScript#14829 https://github.com/microsoft/TypeScript/issues/14829要求这样的非推理类型参数用法。这个想法是应该有一些类型函数称为NoInfer<T>其中类型NoInfer<T>最终评估为T, 但只有after发生了类型推断。然后你会这样写:

class Digraph<K extends string> {
    constructor(readonly adjacencyList: Record<K, NoInfer<K>[]>) { }

    getNeighbours(k: K): K[] {
        return this.adjacencyList[k];
    }
}

一切都应该正常。


虽然没有official的版本NoInfer存在,microsoft/TypeScript#14829 中提到了一些适用于某些用例的用户实现。那个我倾向于推荐 https://github.com/microsoft/TypeScript/issues/14829#issuecomment-504042546 is:

type NoInfer<T> = [T][T extends any ? 0 : never];

条件类型的评估T extends any ? 0 : never是(目前用于 TS4.2)deferred until T是一种特定类型。所以虽然NoInfer<T>最终将评估为T,编译器看不到这一点。

希望 microsoft/TypeScript#14829 最终能够得到正式的实现,这样那里提到的解决方法就可以被放弃而代之以它。或者至少现有的解决方法将升级为受支持的功能。 (这type NoInfer<T> = T & {}版本是尽可能得到支持 https://github.com/microsoft/TypeScript/issues/14829#issuecomment-320754731,但不幸的是这不适用于您的用例。)


无论如何,你可以检查一下这个定义NoInfer<T>将在示例代码中按照您想要的方式运行:

let digraph = new Digraph({
    a: ['b'],
    b: [],
}); // okay, Digraph<"a" | "b">

let badDigraph = new Digraph({
    a: ['c'], // error, "c" is not assignable to "a" | "b"
    b: []
})

Playground 代码链接 https://www.typescriptlang.org/play?#code/C4TwDgpgBAcg9gSQHYDMICcA8AVAfFAXigG1sBdUqCAD2AiQBMBnKAQyRCgH4oAGKAFxQkEAG4YyAbgBQ0gMYAbVkxYARAJYBzdKzAALTAGkqtesyhNg6dUk34A3tKjOocuEkvoArnOBx0ABToEKwM7gqcoQBWrHL0ciAAMuqWQgBKEG7oDEYANLCIqBhGuMRkuACUUPZQAL6yLlCaEMAwEFp6AEZwXuhMAQDWQoYVw2XVTo0uwcC9SFDAeikAdNGx8UkpwMQDUpPO9fXSCi1QDFo6+oTCEADuUBraunoBjo2sQsQA5J1fZLn7KCdT7-aS1CqSKAAeihUDgA1YIHyj0uBgARKw0VAAD5QNGdNG4WQnYBA0Io57XET3Cn6V6Aj4kL5yP75GFUdDofz5NFyLEpYRwUnKJhaJCsTonBZwPGYnF4gmA4EkMhgirSIA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从键而不是值推断类型参数? 的相关文章

随机推荐

  • Javascript 数组是原始数组吗?字符串?物体?

    数组只是伪装的对象吗 为什么 为什么不呢 它们以什么方式 这样 不是 我一直认为 JS 中的数组和对象本质上是相同的 主要是因为访问它们是相同的 var obj I me var arr new Array arr you them con
  • 不确定为什么变量未定义。可能的范围问题?

    如果你看一下下面的函数 在第 11 行 它alert template 它打印undefined If I alert template 在ajax成功回调中 它打印没有问题 由于模板是在函数顶部定义的 因此这不应该在整个函数中是全局的吗
  • Windows 应用商店应用程序的日志记录框架

    我正在寻找将日志记录和检测构建到我的 Windows 应用商店应用程序中 对于 Windows 应用商店应用程序的良好日志记录框架有什么建议吗 我知道我可以通过写入文件或 Azure 存储来推出自己的产品 很好奇是否已经有任何东西 Go f
  • 从 Ruby 块中提取 AST

    是否有可能从 Ruby 本身获取一个块的 AST 我已经研究过 ParseTree 和 ruby parser 但它们似乎都对 Ruby 1 9 2 提供了粗略的支持 根据我读到的内容 我需要一些与 1 9 2 配合良好的东西 Ripper
  • 适用于 Windows 的 Zeromq PHP 扩展

    我正在使用配置了 IIS 7 5 的 Zend 服务器 我搜索了 edit Zeromq php 扩展 我找到了这些http valokuva org builds http valokuva org builds and http sna
  • 支持 Git 的开源 IDE [已关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我无法找到支持 Git 的开源 IDE 有什么可以给我指点或推荐的吗 有一个Eclipse 插件正在进行中 http www eclips
  • 什么是命名空间污染?

    命名空间污染 一词是什么意思 为什么将方法设为静态有助于防止它 这个问题 https stackoverflow com questions 8862665 what does it mean global namespace would
  • 使用 Firebase 使 URL 过期

    如何创建指向 Firebase 数据的临时 URL 但数据 和 URL 将在特定时间 即 5 分钟或 15 分钟 后被销毁 根据数据的存储方式 有几种不同的选项可用于按时间戳删除数据 假设数据未排序 并且您已将时间戳存储为每个记录中的字段
  • 如何将 javascript 中的数字数组转换为字符串?

    就像我有var arr 1 2 3 4 5 我希望这成为arr 1 2 3 4 5 我尝试使用 var x arr 0 toString outputs 1 但当我这样做时typeof x它输出 数字 当我这样做时我该如何转换它typeof
  • 如何从文本文件中删除非 UTF-8 字符

    我有一堆以 utf 8 编码的阿拉伯语 英语 俄语文件 尝试使用 Perl 脚本处理这些文件时 出现以下错误 Malformed UTF 8 character fatal 手动检查这些文件的内容 我发现其中有一些奇怪的字符 现在我正在寻找
  • java.lang.IllegalArgumentException:名称

    它在 Eclipse 中工作正常 但是当我创建 jar 并运行它时会给我这个异常 这是我正在使用的非 Web Spring Boot 应用程序 我应该作为独立 jar 运行 java lang IllegalArgumentExceptio
  • 如何在结束循环之前查看生成器的打印输出?

    我正在尝试在处理大量数据的生成器内打印调试信息 但是 只有当生成器完成时我才能看到结果 我使用的是python 3 我的代码如下 def generator while 1 print end time sleep 1 yield 1 fo
  • 使用 Jenkins 进行发布管理有哪些选项

    我正在评估 Jenkins 和 Apache Continuum 等构建引擎 我们的大部分构建都使用 Maven Jenkins 有哪些用于发布管理的选项 我所说的发布管理是指从源代码控制中的分支创建发布 然后更新 Maven 中的版本标签
  • 使用 GWT CellTableBuilder 按需构建自定义行

    GWT 2 5 RC 中引入了 CellTableBuilder API 但尚未提供全面的文档 是否有使用 CellTableBuilder 实现按需自定义行构建的教程 示例 到目前为止我发现的唯一例子就是这个http showcase2
  • 在大文件中进行搜索的最佳方法是什么?

    我希望对大文件 gt 4GB 应用 KMP 或类似 搜索 我预计这会给我带来问题 我无法将其全部复制到内存中 因为那里没有足够的空间 我的问题是 进行此搜索的最佳方法是什么 我是否应该简单地创建一个 FILE 并直接在文件中进行搜索 是否应
  • 如何组合数据然后分离连接的数据?

    我想将一系列数据合并到一个单单元格 G5 中 然后我想将Value G5拆分为原始形式 太感谢了 https docs google com spreadsheets d 1sVrpPvtQPG0Zw2Ar UxPHXNN0atEdQNX
  • PHP 中有从数组中提取“列”的函数吗?

    我有一个数组的数组 具有以下结构 array array page gt page1 name gt pagename1 array page gt page2 name gt pagename2 array page gt page3 n
  • Cobertura 如何与 JUnit 配合使用?

    我不明白Cobertura如何与JUnit合作 据我了解 cobertura 修改编译的字节代码并在该字节代码中插入它自己的命令 好的 之后 我们运行 Junit 框架并对其进行测试 谁能解释一下 cobertura 在什么时候获取执行了哪
  • 是否有一个 Python 习惯用法可以通过短路来评估函数/表达式列表?

    我写了一个简单的脚本来解决 逻辑谜题 这是学校里的谜题类型 你会被赋予许多规则 然后必须能够找到诸如 有五个音乐家 名字分别为 A B C 之类的问题的解决方案 D E 在一场音乐会上演奏 每人一个接一个地演奏 如果 A 在 B 之前演奏
  • 如何从键而不是值推断类型参数?

    我有一个表示有向图结构的类 它是具有一个类型参数的通用类K extends string对于节点名称 图表是通过传递一个对象来构造的 例如 a b b 在这个最小的例子中代表两个节点a and b 有一条边a b class Digraph