【问题标题】:Precise overloaded function calls in TypeScriptTypeScript 中精确的重载函数调用
【发布时间】:2014-05-02 12:07:40
【问题描述】:

我是 TypeScript 的新手,正在尝试将它与 AngularJS 一起使用。这是一个困扰我的情况,因为我无法从编译器中得到错误。

在 Angular (AFAIK) 中,资源提供者有一个 get() 方法,它返回一个 T 的实例,T 是一个类型参数。此方法有许多其他重载,并且可以接受 paramsdata 参数,并可能接受带有如下签名的成功和错误处理程序:

interface IResourceSuccessCallbackFunction<T> {
    (value: T, responseHeaders: Array<string>): void;
}

interface IResourceErrorCallbackFunction {
    (httpResponse: string): void;
}

我从 corresponding declaration file at DefinitelyTyped 中获得灵感,为 get 函数提出了这些重载:

interface IResourceClass<T> {
    get(): T;
    get(dataOrParams: any): T;
    get(dataOrParams: any, success: IResourceSuccessCallbackFunction<T>): T;
    get(success: IResourceSuccessCallbackFunction<T>, error?: IResourceErrorCallbackFunction): T;
    get(params: any, data: any, success?: IResourceSuccessCallbackFunction<T>, error?: IResourceErrorCallbackFunction): T;
}

我的问题是这些定义允许我写这样的东西:

var resourceService: IResourceClass<number> = null;
var res1 = resourceService.get({ id: 1000 }, function() {
    console.log("fail");
});
var res2 = resourceService.get(function(p: Phone) {
    console.log(p);
}, function() {
    console.log("fail");
});

显然,对于res1,程序员犯了一个错误,将错误处理程序作为第二个参数传递,忘记了成功处理程序;对于res2,假定的成功处理程序接受错误的类型Phone 而不是number

现在,我知道为什么这两个调用会编译并且是有效的:最后一个重载版本总是匹配的,因为它允许两个 any 参数和两个可选参数,这里不存在。所以我正在寻找一种方法来定义可以捕获这些错误的重载变体。例如,将 any 替换为“不是函数”的类型,或者使用其他技巧。

这可能吗?

【问题讨论】:

  • 您希望在编译时捕获这些错误,对吧?你绝对是对的,any 太放纵了。
  • 是的,我想在编译时得到这些错误。

标签: angularjs typescript overloading


【解决方案1】:

如果可能,请使用any 删除重载。我不确定这是否适用于这种情况;这取决于 API 的工作方式。

res1 总是可以的,因为您不需要 在 TypeScript 中使用参数(想象一下,如果您必须对 Array#forEach 进行三参数回调,那将是多么烦人) .

对于res2,您有时可以通过添加“陷阱”重载来改善这种情况:

interface IResourceClass<T> {
    get(): T;
    get(success: IResourceSuccessCallbackFunction<T>, error?: IResourceErrorCallbackFunction): T;
    get(otherFunction1: (...a: any[]) => void, otherFunction2: (...a: any[]) => void): { YOU_HAVE_FAILED: {}; };
    get(dataOrParams: any): T;
    get(dataOrParams: any, success: IResourceSuccessCallbackFunction<T>): T;
    get(params: any, data: any, success?: IResourceSuccessCallbackFunction<T>, error?: IResourceErrorCallbackFunction): T;
}

var resourceService: IResourceClass<number> = null;
var res1 = resourceService.get({ id: 1000 }, function() {
    console.log("fail");
});
// res2: { YOU_HAVE_FAILED: {} }
var res2 = resourceService.get(function(p: Phone) {
    console.log(p);
}, function() {
    console.log("fail");
});

这不会立即成为编译错误,但任何实际使用 res2 都会出错。

【讨论】:

  • 谢谢。 “陷阱”超载的想法很有趣。定义例如interface Nothing {} 并返回Nothing 怎么样?这会是个坏主意吗?顺便说一句,重载决议严格按照声明顺序测试不同的签名,对吧?
  • 是的,签名是按顺序严格测试的。 Nothing 的问题是你可以将任何东西分配给它to;拥有 FAIL 成员可以防止这种情况发生。
  • 我明白了,谢谢你的帮助。该语言是否有可能有一天会包含这样的“错误”类型——或者让我们以某种方式更正式地以类似的方式指定无效的函数签名?
  • 还有一个问题:(...a: any[]) =&gt; void 是否匹配每个函数,从而充当函数类型通配符?
猜你喜欢
  • 2016-12-20
  • 2017-07-26
  • 2012-10-24
  • 2011-06-08
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
相关资源
最近更新 更多