繁体   English   中英

TypeScript泛型:泛型函数类型和对象文字类型的调用签名不相等(类型'T'不能分配给类型'T')

[英]TypeScript generics: Inequivalence of generic function type and call signature of an object literal type (Type 'T' is not assignable to type 'T')

我正在编写一个RxJS运算符,它等待输入运算符完成,然后将switchMap转换为第二个运算符(与switchMap一样,它是动态生成的)。 我想出了我的代码的两个版本,一个版本有效,一个版本无效,而我正在努力地思考为什么这样做。

起作用的版本:

import { Observable } from "rxjs"; // OperatorFunction,
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";

// This definition of OperatorFunction is more or less equivalent to the
// definition in rxjs/src/internal/types.ts
interface OperatorFunction<T, S> {
    (input: Observable<T>): Observable<S>;
}

interface ObservableGenerator<T, S> {
    (value: T): Observable<S>;
}

export function switchMapComplete<T, S>(project: ObservableGenerator<T, S>): OperatorFunction<T, S> {
    function mapper(obs1: Observable<T>): Observable<S> {
        return obs1.pipe(
            defaultIfEmpty(null),
            last(),
            switchMap(project)
        );
    }

    return mapper;
}

该版本不起作用(请注意,唯一更改的是OperatorFunctionOperatorGenerator的定义):

import { Observable } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";

type OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>;

type ObservableGenerator2<T, S> = <T, S>(value: T) => Observable<S>;

export function switchMapComplete2<T, S>(project: ObservableGenerator2<T, S>): OperatorFunction2<T, S> {
    function mapper(obs1: Observable<T>): Observable<S> {
        return obs1.pipe(
            defaultIfEmpty(null),
            last(),
            switchMap(project)
        );
    }

    return mapper;
}

后者导致编译器抛出以下异常:

error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<S>'.
  Type '{}' is not assignable to type 'S'.
util.ts(49,5): error TS2322: Type '(obs1: Observable<T>) => Observable<S>' is not assignable to type 'OperatorFunction2<T, S>'.
  Types of parameters 'obs1' and 'obs' are incompatible.
    Type 'Observable<T>' is not assignable to type 'Observable<T>'. Two different types with this name exist, but they are unrelated.
      Type 'T' is not assignable to type 'T'. Two different types with this name exist, but they are unrelated.

我对此感到非常惊讶,并且花了很长时间才提出工作版本,因为TypeScript文档说这两个版本应该等效 (据我所知)。

我很高兴收到任何关于为什么我的等效性崩溃的指示。

PS:对于需要类似于我的RxJS运算符的任何人,这是另一个(有效的)解决方案,它稍微简单一些,并充分利用RxJS已经提供的类型:

import { Observable, ObservableInput, OperatorFunction, pipe } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";

export function switchMapComplete<T, S>(project: (value: T) => ObservableInput<S>): OperatorFunction<T, S> {
    return pipe(
        defaultIfEmpty(null),
        last(),
        switchMap(project)
    );
}

首先,您应该将类​​型OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>更改为type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>因为您没有在类型别名的定义中使用外部TS 内部的<T, S>遮盖了外部名称。 然后对ObservableGenerator2进行类似的更改。

请注意, type F<T> = (x:T) => void不等于type G = <T>(x:T)=>void TypeScript不允许使用完全通用的值 类型F是泛型的,是指具体功能,并且必须为F提供类型参数才能使用( F bad, F<string> good)。 类型G是引用泛型函数的具体类型,不能为G提供类型参数( G<string>不好, G很好)。 类型F<string>是具体的,并且只能接受string函数输入。 类型G的值是通用的,可以接受任何输入。

不是说类型是完全不相关的。 他们只是不相等。 我希望可以为您提供更多帮助,但是我没有在任何地方安装RxJS,因此以下代码可能仍然有错误。 不过,我会在这里告诉您我要尝试的方法:

// concrete types referring to generic functions
type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>;
type ObservableGenerator2 = <T, S>(value: T) => Observable<S>;

// a concrete function which takes a generic function and returns a generic function
export function switchMapComplete2(project: ObservableGenerator2): OperatorFunction2 {
  // a generic function
  function mapper<T, S>(obs1: Observable<T>): Observable<S> {
    return obs1.pipe(
      defaultIfEmpty(null),
      last(),
      switchMap(project)
    );
  }

  return mapper;
}

希望您能走上正确的道路。 您可能需要深入研究mapper的实现并修复更多签名。 无论如何,祝你好运!

TypeScript中的通用函数类型通常写为

type OperatorFunction2<T, S> = (obs: Observable<T>) => Observable<S>;

语法

type OperatorFunction2 = <T, S>(obs: Observable<T>) => Observable<S>;

泛型参数在类型定义中出现“内联”的位置也是有效的,但是由于某种原因,它与为泛型类型显式给出泛型参数的类型定义并不完全等效。 当您没有嵌套通用参数的type定义时,必须在嵌套在另一个定义中的类型注释中提供显式类型时,第二种形式有时很有用。

当您结合两者

type OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>;

然后,如jcalz所指出的,您将获得两个独立的通用参数集,它们具有相同的名称TS ,彼此不相关。

对于您的示例,您可以仅使用第一种语法:

import { Observable } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";

type OperatorFunction2<T, S> = (obs: Observable<T>) => Observable<S>;

type ObservableGenerator2<T, S> = (value: T) => Observable<S>;

export function switchMapComplete2<T, S>(project: ObservableGenerator2<T, S>): OperatorFunction2<T, S> {
    function mapper(obs1: Observable<T>): Observable<S> {
        return obs1.pipe(
            defaultIfEmpty(null),
            last(),
            switchMap(project)
        );
    }

    return mapper;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM