所以你的问题是有多个候选推理站点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