如何声明泛型class泛型?

How to declare generic class generic?

我正在尝试设计一种方法来声明一个函数,该函数可以 return Promise 或 rxjs Observable 或具有特定 return 类型的大多数流,但我不知道合适的在打字稿中声明此函数的方法。

一般来说,我希望在我的代码中是这样的:

class Action<T> {
    dispatcher: Function
    constructor(dist) {
        this.dispatcher = dist
    }

    f = <T>(s: string): T<string> => this.dispatcher('hello'+s)
}

In this way I get the error: 'T is not generic'

对我来说,T 可以是 Promise、Observable 或 Stream

如果我能够拥有与此类似的东西,我可以声明一个特定的调度程序,return 根据我的声明方式

我想要的值
const promiseDispacher = (x:any)=>Promise.resolve(x)
const observableDispacher = (x:any)=>Observable.of(x)

我想要的是当我调用函数 f 时能够以不同的方式使用

 const a = new Action<Promise>(promiseDistpacher)
 a.f('random string').then((s: string)=>{
   ....
 })

 const a = new Action<Observable>(observableDistpacher)
 a.f('random string').subscribe((s: string)=>{
   ....
 })

已更新

f 是一个函数,它执行一些操作并使用调度程序将结果包装在特定的 T (Promise 或 Stream)中并 returned 返回给 class 执行函数

尽管我不确定你在做什么,但我会尝试回答这个问题。作为第一步,让我们将 T 设为由传入的调度程序 return 生成的泛型类型,类似于 Promise<any>Observable<any>ReadableStream<any>:

class Action<T> {
  dispatcher: (x: any) => T;
  constructor(dist: (x: any) => T) {
    this.dispatcher = dist
  }
  f = (s: string) => this.dispatcher('hello' + s);
}

const promiseDispatcher = (x: any) => Promise.resolve(x)
const a = new Action(promiseDispatcher);
a.f("random string").then((s: string) => {
  // ...
}); // works

这现在可以工作了,Action<T>f 类型被推断为 (s: string) => T 类型,因为 aAction<Promise<any>>,那么a.f(s)就是一个Promise<any>。请注意,尽管 f 在其 return 类型中有一个 T,但 f 本身并不是您认为的通用函数。通用参数在 class 上,一旦你有了 class 的具体实例,它的 f 函数也是一个具体函数类型.


这里的一个问题是您可能并不真的希望 a.f(s) 成为 Promise<any>,而是希望看到 Promise<string>。事实证明,由于 TypeScript 当前不支持 higher kinded types very much, there's no general way to say to make T something like Promise or Observable or ReadableStream, which are themselves generic types. With conditional types,您可以选择一些硬编码类型,如 Promise<any>Observable<any>ReadableStream<any>,并将它们转换为 Promise<string>Observable<string>ReadableStream<string>,分别为:

type AppliedToString<T> =
  T extends Promise<any> ? Promise<string> :
  T extends Observable<any> ? Observable<string> :
  T extends ReadableStream<any> ? ReadableStream<string> :
  T;

现在,如果我们 constrain T 那些硬编码的类型并使用上面的类型函数,我们应该得到类似于您想要的类型 f:

// constrain T
class Action<T extends Promise<any> | Observable<any> | ReadableStream<any>> {
  dispatcher: (x: any) => T;
  constructor(dist: (x: any) => T) {
    this.dispatcher = dist
  }
  // assert return type of f as AppliedToString<T>
  f = (s: string) => this.dispatcher('hello' + s) as AppliedToString<T>;
}
const promiseDispatcher = (x: any) => Promise.resolve(x);
const a = new Action(promiseDispatcher);
a.f("random string").then((s: string) => {
  // ...
}); // works

现在,如果您检查 a.f 的 return 类型,您会发现它是 Promise<string>

这样做的缺点是您需要维护一个硬编码列表,而且它也不是特别安全的类型,因为它允许您传入 return 是 Promise<number> 的调度程序并将其视为 Promise<string>... 会在运行时爆炸。


如果我想变得更简单、类型更安全,我会将 T 限制为 Promise<string>Observable<string>ReadableStream<string> 并忘记映射,但是要求传入的调度程序采用 string 和 return T:

class Action<T extends Promise<string> | Observable<string> | ReadableStream<string>> {
  dispatcher: (x: string) => T;
  constructor(dist: (x: string) => T) {
    this.dispatcher = dist
  }
  f = (s: string) => this.dispatcher('hello' + s);
}
// note that x is type string in this:
const promiseDispatcher = (x: string) => Promise.resolve(x)
const a = new Action(promiseDispatcher);
a.f("random string").then((s: string) => {
  // ...
})

好的,希望其中一项或多项对您有所帮助。祝你好运!