TypeScript Generics在VS Code中始终显示为“any”

时间:2017-10-16 16:33:35

标签: typescript generics

我正在使用带有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>,则会显示TdataInTcallback的数据类型,localscd也是正确的类型。

我怎样才能使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() );
} );

2 个答案:

答案 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只有一个泛型类型参数。