How to understand complicated typescript generic types?

Rak*_*shi 7 typescript reactjs typescript-generics angular rxjs6

I was checking RxJS api documents. I always face problem in understanding the weird syntax written on the top, Which is like below as an example:

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

I wanted to understand this kind of syntax and further write it by my own.

So, It will be great help if anyone explain what's going on in above example.

yur*_*zui 9

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

让我们分解一下。

好的,那是一个功能

function combineLatest(args): Result
Run Code Online (Sandbox Code Playgroud)

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

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

function combineLatest<T>(args): Result
                      /\
           now it's a generic function
Run Code Online (Sandbox Code Playgroud)

T是一个类型变量,它使我们能够捕获用户提供的类型,以便以后可以使用该信息。例如,我们可以将其T用作返回类型:

function combineLatest<T>(args): T
Run Code Online (Sandbox Code Playgroud)

这样下面的调用:

combineLatest<string>(someParams) // returns `string`
Run Code Online (Sandbox Code Playgroud)

string因为我们显式设置T为,所以将为我们提供type的结果string

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

function combineLatest<T>(arg: T): T
Run Code Online (Sandbox Code Playgroud)

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

combineLatest('someStr') // returns `string`
Run Code Online (Sandbox Code Playgroud)

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

我们可以根据需要使用任意多个类型变量。我们也可以随便给他们打电话。

function combineLatest<Type1, Type2, ...>(...)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

现在,编译器知道arg具有的name属性string


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

combineLatest<O extends ObservableInput<any>, R>(...): Observable<R>
Run Code Online (Sandbox Code Playgroud)

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

  • O类型变量,代表Observable。仅限于ObservableInput<any>
  • R 代表结果

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

combineLatest<any, MyClass>(...)  // returns Observable<MyClass>
Run Code Online (Sandbox Code Playgroud)

现在让我们看一下该函数可以采用的参数:

...observables: (O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike)[]
Run Code Online (Sandbox Code Playgroud)

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

...observables: CombinedType[]
Run Code Online (Sandbox Code Playgroud)

这意味着该combineLatest函数可以接受零个或多个参数,这些参数以后将被收集到一个变量中observables

combineLatest();                 // without parameters
combineLatest(obs1);             // one parameter
combineLatest(obs1, obs2, ..etc) // many parameters
Run Code Online (Sandbox Code Playgroud)

那这个参数的类型是什么

           CombinedType

O | ((...values: ObservedValueOf<O>[]) => R) | SchedulerLike
Run Code Online (Sandbox Code Playgroud)

有可能:

  • O类型变量的类型,它是ObservableInput<any>我们前面讨论的类型

  • 或者它可以是(...values: ObservedValueOf<O>[]) => R接受零个或多个type参数ObservedValueOf<O>并返回Rtype变量type的函数。请注意,此返回类型可用于推断combineLatest函数的返回类型。

  • 或者它可以是SchedulerLike接口的类型。


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