ReturnType 此索引方法和点表示法之间的差异

问题描述 投票:0回答:1

来自这里如何推断类方法未知的返回类型并在属性中使用它

尝试推断

initialize
方法返回什么并将该类型应用于
prop

此代码有效:

class Base {
  method_1() {}
}

class Child extends Base {
  method_2() {}
}

abstract class AbstractClass {
  prop: ReturnType<this['initialize']>

  abstract initialize(): Base
}

class UserClass2 extends AbstractClass {
  initialize() {
    return new Child()
  }

  someMethod() {
    this.prop.method_1()  // Valid, no TS error
    this.prop.method_2()  // Valid, no TS error
  }
}

这始终返回基本类型:

class Base {
  method_1() {}
}

class Child extends Base {
  method_2() {}
}

abstract class AbstractClass {
  prop: ReturnType<typeof this.initialize>

  abstract initialize(): Base
}

class UserClass2 extends AbstractClass {
  initialize() {
    return new Child()
  }

  someMethod() {
    this.prop.method_1()  // Valid, no TS error
    this.prop.method_2()  // Error!
  }
}

ReturnType
中使用索引方式
ReturnType<this['initialize']>
和点符号
typeof
ReturnType<typeof this.initialize>
有什么区别?

typescript types typescript-typings
1个回答
0
投票

this
类型是隐式通用的:

多态this

类型
microsoft/TypeScript#4910中实现,“通过为每个类和接口提供隐含的[generic]类型参数,该参数约束到包含类型本身”。从某种意义上说,你的课程相当于这些:

abstract class AbstractClass<T extends AbstractClass<T>> { prop!: ReturnType<T['initialize']>; abstract initialize(): Base } class UserClass2<T extends UserClass2<T>> extends AbstractClass<T> { initialize() { return new Child() } someMethod(this: T) { this.prop.method_1() this.prop.method_2() } }


使用特定键对泛型进行索引会扩大约束

类型

this['initialize']

索引访问类型,意思是“initialize
类型的
this
属性的类型”。该索引访问类型也是隐式通用的。在 
AbstractClass
 的子类中,它将引用该子类的 
initialize
 属性。

您可能期望,如果您有一个类型为

this

 的值(例如名为 
this
 的值)并且您使用键 
'initialize'
 对它进行索引,您将获得该索引访问类型,因此 
typeof this.initialize
this['initialize']
 相同。但事实并非如此:

abstract class AbstractClass { abstract initialize(): Base goodInit!: this['initialize']; // (property) AbstractClass.goodInit: this["initialize"] badInit!: typeof this.initialize // (property) AbstractClass.badInit: () => Base }
您可以看到 

badInit

() => Base
 类型,它完全独立于 
this
,而 
goodInit
 正如预期的那样是 
this["initialize"]
 类型。
发生这种情况的原因是,当您有一个通用值并使用非通用键对其进行索引时,编译器将自动将通用值扩大到其约束。所以在

AbstractClass

内部,this.initialize 的类型就是

() => Base
。因此
typeof this.initialize
不是多态的,子类不会看到任何不同。请参阅
microsoft/TypeScript#33181 上的评论
之所以出现that,本质上是为了性能和易用性。如果每次提到 

this

都保持通用,那么编译器将不得不在各处合成大量通用类型,从而损害性能。此外,这将使使用泛型值变得更加困难,因为它们永远不会“兑现”到特定类型。因此,如果要改变这一点,编译器会变得更慢,并且会出现很多代码损坏。


将它们放在一起,你就会得到答案;和

ReturnType

关系不大。就是this["initialize"]

typeof this.initialize是两种不同的类型;前者是通用的,而后者则不是。
Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.