【问题标题】:How to understand complicated typescript generic types?如何理解复杂的打字稿泛型类型?
【发布时间】:2019-11-24 20:10:11
【问题描述】:

我正在检查 RxJS api 文档。我在理解顶部写的奇怪语法时总是遇到问题,如下所示:

combineLatest<O extends ObservableInput<any>, R>(...observables: (O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike)[]): Observable<R>

我想了解这种语法并进一步自己编写。

所以,如果有人解释上面示例中发生的事情,那将是非常有帮助的。

【问题讨论】:

  • 在这里询问工具、库或场外资源是题外话
  • 好的。我也要求解释上面的代码。

标签: angular reactjs typescript rxjs6 typescript-generics


【解决方案1】:

function combineLatest&lt;O extends ObservableInput&lt;any&gt;, R&gt;(...observables: (O | ((...values: ObservedValueOf&lt;O&gt;[]) =&gt; R) | SchedulerLike)[]): Observable&lt;R&gt;

让我们分解一下。

好的,这是一个函数

function combineLatest(args): Result

它接受一些参数并返回Result类型的结果

但它也是一种特殊的函数,称为generic 函数。 泛型的目的是在成员之间提供有意义的类型约束。

function combineLatest<T>(args): Result
                      /\
           now it's a generic function

这里的T 是一个类型变量,它允许我们捕获用户提供的类型,以便我们以后可以使用该信息。例如,我们可以使用T作为返回类型:

function combineLatest<T>(args): T

以便以下调用:

combineLatest<string>(someParams) // returns `string`

将给我们string 类型的结果,因为我们将T 明确设置为string

我们还可以将 T 类型变量用于函数的任何参数。

function combineLatest<T>(arg: T): T

现在我们可以使用类型参数推断

combineLatest('someStr') // returns `string`

也就是说,我们告诉编译器根据我们传入的参数类型自动为我们设置T的值。我们传递了string,所以我们得到了string .

我们可以使用任意数量的类型变量。我们也可以随意称呼它们。

function combineLatest<Type1, Type2, ...>(...)

泛型很棒,有时我们想用我们传入的参数进行一些操作:

function combineLatest<T>(arg: T): T {
  arg.name = arg.name.toLowerCase(); // Property 'name' does not exist on type 'T'
  return arg;
}

如您所见,编译器无法理解arg 的类型。为了解决这个问题,我们可以在 extends 运算符的帮助下为 T 类型变量表示约束:

interface ItemWithName {
  name: string;
}
function combineLatest<T extends ItemWithName>(arg: T): T {
  arg.name = arg.name.toLowerCase();
  return arg;
}

现在编译器知道 arg 具有 stringname 属性。


现在让我们回到我们最初的声明:

combineLatest<O extends ObservableInput<any>, R>(...): Observable<R>

我们可以在这里看到这个函数使用了两个类型变量:

  • O 代表 Observable 的类型变量。它被限制为ObservableInput&lt;any&gt; 的类型
  • R 代表结果

combineLatest 函数的结果应该是 Observable 类型的 R。例如,我们可以通过调用这个函数来强制该类型:

combineLatest<any, MyClass>(...)  // returns Observable<MyClass>

现在让我们看看这个函数可以带的参数:

...observables: (O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike)[]

我们可以在这里看到rest parameters 运算符。让我们简化上面的表达式,让我们想象一下:

...observables: CombinedType[]

这意味着combineLatest 函数可以接受零个或多个参数,这些参数将在稍后聚集到一个变量observables

combineLatest();                 // without parameters
combineLatest(obs1);             // one parameter
combineLatest(obs1, obs2, ..etc) // many parameters

那么这个参数的类型是什么

           CombinedType

O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike

可以是:

  • O 类型变量的类型被限制为我们之前讨论过的ObservableInput&lt;any&gt; 类型

  • 它可以是函数(...values: ObservedValueOf&lt;O&gt;[]) =&gt; R,它接受零个或多个ObservedValueOf&lt;O&gt;类型的参数并返回R类型的变量类型。注意这个返回类型可以用来推断combineLatest函数的返回类型。

  • 可以是SchedulerLike接口类型。


我认为如果将 TypeScript 类型声明拆分成小块,理解它们应该没有任何问题。

【讨论】:

  • 非常感谢@yurzui。这是非常有用的解释。
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 2020-06-29
  • 1970-01-01
  • 2018-04-27
  • 2017-09-15
相关资源
最近更新 更多