class A {}
class B {}
class C {}
class D {}


class Example {
  public static ClassesByName = { A:A,B:B,C:C,D:D };

  public stringToClass<
    Hash extends typeof Example.ClassesByName,
    T extends keyof Hash,
  >(className: T) {

    const klass = Example.ClassesByName[className]; //<- Type 'T' cannot be used to index type '{ A: typeof A; B: typeof B; C: typeof C; D: typeof D; }'.

  }
}

Playground

我得到了这个错误:

Type 'T' cannot be used to index type '{ A: typeof A; B: typeof B; C: typeof C; D: typeof D; }'.

在这条线上:

const klass = Example.ClassesByName[className];

className是延伸keyof HashT类型.Hashtypeof Example.ClassesByName的延伸.

一切都是相连的,那么为什么Typescrip告诉我不能使用className来索引Example.ClassesByName,以及我如何修复它?

推荐答案

代码的问题是stringToClass()generic了. 通过使用H extends typeof Example.ClassesByName,你允许它比那个类型更大,因此可能有额外的键. 也就是说,有人可以打电话

const whoops = Object.assign({ a: 123 }, Example.ClassesByName);
const instance = new Example();
const hmm = instance.stringToClass<typeof whoops, "a">("a");

所以whoops在关键字a处有一个额外的属性,但它仍然可以赋值给typeof Example.ClassesByName.因此,您可以将其类型作为第一个类型参数传递给stringToClass(),因此将"a"作为其第二个类型参数传递(因为它是该类型的有效键),因此className可以是"a".但在stringToClass()的内部:

public stringToClass<
  H extends typeof Example.ClassesByName,
  K extends keyof H,
>(className: K) {
  const klass = Example.ClassesByName[className]; // error!
}

你不是用className索引generic,你只是索引Example.ClassesByName编译器不知道类型KclassName是否实际上是Example.ClassesByName的键,因为它不知道有人会为H传递什么额外的键. 所以这是个错误.


这里的修复方法是在K中只使stringToClass()成为通用的,即从constrainedkeyof typeof Example.ClassesByName.这意味着K将是Example.ClassesByName的索引,您的实现将编译:

public stringToClass<
  K extends keyof typeof Example.ClassesByName,
>(className: K) {
  const klass = Example.ClassesByName[className]; // okay
}

现在你不能再叫它坏方法了,因为"a"不是Example.ClassesByName的关键字,你也没有办法传入typeof whoops或其他任何东西:

const instance = new Example();
const hmm = instance.stringToClass<"a">("a"); // error!

Playground link to code

Typescript相关问答推荐

如何使打包和拆包功能通用?

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

如果存在ts—mock—imports,我们是否需要typescpt中的IoC容器

类型{...}的TypeScript参数不能赋给类型为never的参数''

为什么TypeScript假设文档对象始终可用?

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

为什么在回调函数的参数中不使用类型保护?

如何使用WebStorm调试NextJS的TypeScrip服务器端代码?

类型脚本满足将布尔类型转换为文字.这正常吗?

Select 下拉菜单的占位符不起作用

如何从扩展接口推断泛型?

TypeError:正文不可用-NextJS服务器操作POST

使用KeyOf和Never的循环引用

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

APP_INITIALIZER在继续到其他Provider 之前未解析promise

如何在省略一个参数的情况下从函数类型中提取参数类型?

编剧- Select 动态下拉选项

使用本机 Promise 覆盖 WinJS Promise 作为 Chrome 扩展内容脚本?

Typescript 编译错误:TS2339:类型string上不存在属性props

React 中如何比较两个对象数组并获取不同的值?