这个 return 类型从不做与只使用接口有什么区别?

What does this return type with never do vs just using an Interface?

在尝试用 Typescript 创建工厂时,我遇到了 this article,我对这部分感到困惑:

  class UserFactory {
  static getUser(k: Keys) : ExtractInstanceType<userTypes> {
    return new userMap[k]();
  }

供参考的类型定义:

type ExtractInstanceType<T> = T extends new () => infer R ? R : never;

我不确定为什么我们需要 ExtractInstanceType 以及为什么我们不想只使用 IStaff:

  class UserFactory {
  static getUser(k: Keys) : IStaff {
    return new userMap[k]();
  }

我也很疑惑Keys在这里说的是什么,我以为它只是userMap可以容纳的字典中的一个键,它应该是一个字符串?

但是当使用该方法时,它是与对象实例一起作为参数使用还是不可能?

const manager = new Manager();
const anotherManger = UserFactory.getUser(manager);

I am not sure why we need ExtractInstanceType & why we don't want to just use IStaff?

因为 userMap 和关联的静态方法的重点是将名称映射到 具体的、具体的 classes,而不是它们的接口实行。如果这些 classes 中的任何一个在通用 IStaff 接口之上实现了 class-specific 的东西(他们几乎肯定会这样做),那么每次您的代码都会被 instanceof 或其他检查所困扰调用不在 IStaff 中的方法,如果您没有通过使用该静态方法缩小类型以满足编译器的要求,将其扼杀在萌芽状态。

I thought it was just one of the keys in the dictionary that userMap can hold, which would be a string?

正如我在对您 的回答的评论中所建议的那样,我认为问题在于您仍在混淆 typesvalues。 TBF 它没有帮助,有一些重叠。

考虑字符串 'a'。在 Typescript 中,有 value 'a' 但也有 literal 类型 'a',它是输入 string:

type a = 'a'
let a: a = 'a'
let s: string = a // note, variable a not string literal a!
const foo = {
  a: 1
}

console.log(foo[a]) // 1
console.log(foo[s]) // type error!

// ok, let's try the string literal 'a'
s = 'a'
console.log(foo[s]) // same type error!
// eff

因为a字面意思是'a',我们可以用它索引foo。但是 s 是一个 mutable 绑定到一个字符串,即使我们设置了 value 也不能用任何旧字符串索引 foo到 'a',即使我们将它设置为 变量 a 具有 类型 asstill a string 编译器无法保证我们不会重新分配非 a 值。 playground

类型可能看起来像值,并且在某些上下文中可能与值具有完全相同的外观,但它们是不是值,值类型也不是。向右移动...

对于对象文字,我们在编译时知道对象中的键,所以如果我们有一个 foo 对象 {a: 'hi', b: 5},那么 keyof typeof foo 就是 'a' | 'b'。 N.B。这些是字符串,但在本例中它们是 types,而不是 Javascript values。博客post中的方法限制了k参数可以传递的值只能是userMap.

的编译时已知键中的值

But when that method is used, is it is used with an object instance as it's parameter or is that not possible?

哦,可以改变方法以那样工作,这有点毫无意义。如果您有一个实例的引用,那么您已经有一个对其构造函数的引用,您不需要查找 table 来创建另一个:

class Foo {}

const foo = new Foo()
const bar = new (foo.constructor as any)()
bar instanceof Foo // true

Playground

同样,userMap 和访问它的静态方法的要点是工厂能够通过 字符串名称class 查找正确的用户 class =68=].