如何声明泛型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
类型,因为 a
是 Action<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) => {
// ...
})
好的,希望其中一项或多项对您有所帮助。祝你好运!
我正在尝试设计一种方法来声明一个函数,该函数可以 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
类型,因为 a
是 Action<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) => {
// ...
})
好的,希望其中一项或多项对您有所帮助。祝你好运!