我正在使用带有VS Code 1.16.1的TypeScript 2.5.3并且我正在尝试创建一个通用函数来接受一个事件处理程序,其中一个参数是特定类型,它应该调用一个回调函数完成后的另一种类型。
示例:
router( 'staff-count', async function<String, Number>(locals, payload, cb) {
let staff = new Staff();
cb( await staff.count() );
} );
我的界面如下所示:
export interface SocketCallback<T> {
(json: T): void;
}
export interface SocketRouter {
(
eventName: string,
handler: {
<TdataIn, Tcallback>(
e: SocketLocals,
payload: TdataIn,
callback: SocketCallback<Tcallback>
): Promise<void>;
}
): void;
}
所以我希望payload
成为String
,回调才能成为Number
。
但是,在VSCode中,它显示回调的所有三个文档都是:any
。如果我删除通用<String, Number>
,则会显示TdataIn
和Tcallback
的数据类型,locals
和cd
也是正确的类型。
我怎样才能使payload
在这种情况下属于String
类型(它实际上是一个JSON对象,但要保持简单......)。
谢谢!
修改
在VS代码中作为示例运行的代码 - 移除<String, Number>
router
调用,例如,payload
显示为TdataIn
。将<String, Number>
保留在那里,它会payload
显示为any
。我应该String
我认为?
export interface SocketCallback<T> {
(json: T): void;
}
export interface SocketRouter {
(
eventName: string,
handler: {
<TdataIn, Tcallback>(
locals: string,
payload: TdataIn,
callback: SocketCallback<Tcallback>
): Promise<void>;
}
): void;
}
class Staff {
public async count (): Promise<number> {
return 3; // would do some db interaction
}
}
let router: SocketRouter = function ( name, cb ) {
// Do something
}
router( 'staff-count', async function<String, Number>(locals, payload, cb) {
let staff = new Staff();
cb( await staff.count() );
} );
答案 0 :(得分:2)
将通用参数放在SocketRouter
接口的方法上,然后在调用router
时指定通用约束。
export interface SocketCallback<T> {
(json: T): void;
}
export interface SocketRouter{
<TDataIn, TCallback>(
eventName: string,
handler: {(
locals: string,
payload: TDataIn,
callback: SocketCallback<TCallback>
): Promise<void>;
}
): void;
}
class Staff {
public async count (): Promise<number> {
return 3; // would do some db interaction
}
}
let router: SocketRouter = function ( name, cb ) {
// Do something
}
router<String, Number>( 'staff-count', async function(locals, payload, cb) {
let staff = new Staff();
cb( await staff.count() );
});
注意:我并不是最初建议的解决方案的粉丝,因为您在创建router
实例后指定了类型,但这取决于您的方式实际上在你的代码中使用它。您还可以将上面的内容与下面的内容混合,在接口类型上指定一个通用参数,在方法上指定另一个通用参数,再次,如果/您想要这样做,实际上取决于您如何看待自己使用它。
为什么不将泛型参数放在接口定义级别,这样可以解决问题。然后,在定义SocketRouter
export interface SocketCallback<T> {
(json: T): void;
}
export interface SocketRouter<TDataIn, TCallback> {
(
eventName: string,
handler: {(
locals: string,
payload: TDataIn,
callback: SocketCallback<TCallback>
): Promise<void>;
}
): void;
}
class Staff {
public async count (): Promise<number> {
return 3; // would do some db interaction
}
}
let router: SocketRouter<String, Number> = function ( name, cb ) {
// Do something
}
router( 'staff-count', async function(locals, payload, cb) {
let staff = new Staff();
cb( await staff.count() );
});
答案 1 :(得分:0)
您的通用设备位于错误的位置。
对于初学者来说,最后在你的async function
上放置泛型是没有意义的,你的意思可能是async function () { bla bla } as (something: Number, somethingElse: String) => void
(即使这也没有意义)
这里的真正问题是它应该是一般推断的回调,而不是处理程序本身(只是将其传递给回调)
你想要这样的东西:
export interface SocketCallback {
<T>(json: T): void;
}
export interface SocketRouter {
(
eventName: string,
handler: {
<TdataIn>(
locals: string,
payload: TdataIn,
callback: SocketCallback
): Promise<void>;
}
): void;
}
class Staff {
public async count () { // no need to provide explicit return type. TS can infer.
return await 3; // would do some db interaction
}
}
let router: SocketRouter = function ( name, cb ) {
// Do something
}
router( 'staff-count', async function(locals, payload, cb) {
let staff = new Staff();
cb( await staff.count() ); // works as expected
} );
重要的部分是:
SocketCallback
不再是通用的,而是由SocketCallback
接口表示的函数本身。这种区别意味着类型参数(重命名为T)可以通过传递给函数的参数来推断。handler
只有一个泛型类型参数。