首页 > 解决方案 > 与只使用接口相比,这种返回类型从不做什么?

问题描述

在尝试在 Typescript 中创建工厂时,我遇到了这篇文章,对此部分感到困惑:

  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);

标签: typescripttypescript-typingstypescript-generics

解决方案


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

因为userMap和相关的静态方法的重点是将名称映射到特定的具体类,而不是它们实现的接口。如果这些类中的任何一个在通用 IStaff 接口之上实现了特定于类的东西(而且它们几乎肯定会),那么instanceof每次你调用一个方法时,IStaff如果你没有将它扼杀在通过使用该静态方法缩小类型以满足编译器的要求。

我以为它只是 userMap 可以保存的字典中的一个键,它是一个字符串?

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

考虑字符串'a'。在 Typescript 中,有'a' 但也有文字类型 'a',它是 type 的子集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用它来索引。But是对字符串的可变绑定,即使我们将设置为 'a',s您也不能使用任何旧字符串进行索引,即使我们将其设置为类型为 a变量,编译器仍然字符串无法保证我们不会重新分配非 a 值。操场foo as

类型可能看起来像值,并且在某些上下文中可能具有与值完全相同的外观,但它们不是值,也不是值类型。一直往前走……

对于对象字面量,我们在编译时就知道对象中的键,所以如果我们有一个 foo 对象,{a: 'hi', b: 5}那么keyof typeof foois 'a' | 'b'。注意那些是字符串,但在这种情况下它们是类型,而不是 Javascript。博客文章中的方法将k参数可以传递的值限制为仅在userMap.

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

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

class Foo {}

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

操场

同样,userMap访问它的静态方法的意义在于工厂能够通过字符串名称查找正确的用户类。


推荐阅读