【问题标题】:How to create a TypeScript interface definition for an overloaded function with string-indexed array?如何为具有字符串索引数组的重载函数创建 TypeScript 接口定义?
【发布时间】:2012-12-10 07:08:33
【问题描述】:

我正在为knockout validation plugin 编写一个 TypeScript 定义文件。我坚持的一件事与该库中如何定义新的验证规则有关。

ko.validation 创建基本同步验证器的方法如下:

ko.validation.rules['myrulename'] = {
    message: 'default message to display when validation fails',
    validator: function (value, params) {
        // use value and params to evaluate rule, 
        // then return true if valid, false if invalid
    }
}

这很简单,但是创建异步验证器的方法略有不同:

ko.validation.rules['myrulename'] = {
    async: true,
    message: 'default message to display when validation fails',
    validator: function (value, params, callback) {
        // use value and params to evaluate rule, 
        // then invoke callback to indicate pass / fail
        // this function does not return a bool (it is void)
    }
}

异步回调可以采用 bool(用于验证通过/失败)或对象字面量(isValid 用于通过/失败,message 用于更改验证消息)。为此,我创建了以下内容:

interface KnockoutValidationAsyncCallbackArgs {
    isValid: bool;
    message: string;
}

interface KnockoutValidationAsyncCallback {
    (result: bool): void;
    (result: KnockoutValidationAsyncCallbackArgs): void;
}

这是我的KnockoutValidationStatic 的精简版,它公开了规则数组。我还为规则数组创建了一个特殊接口来指定字符串索引:

interface KnockoutValidationRulesArray extends Array {
    [index: string]: KnockoutValidationRule;
}

interface KnockoutValidationStatic {
    rules: KnockoutValidationRulesArray;
    ... other members defined on this interface
}

interface KnockoutStatic {
    validation: KnockoutValidationStatic;
}

我坚持的是KnockoutValidationRule。我尝试了以下方法:

interface KnockoutValidationRule {
    async?: bool;
    message: string;
    validator(value: any, params: any): bool;
    validator(value: any, params: any, callback: KnockoutValidationAsyncCallback): void;
}

这适用于同步验证器声明。但是,当我创建一个异步的时,我收到以下错误:

无法转换 '{ message: string;验证器:(值:任何,参数: 任何,回调:KnockoutValidationAsyncCallback) => void }' 到 'KnockoutValidationRule':类型'{的属性'validator'的类型 消息:字符串;验证器:(值:任意,参数:任意,回调: KnockoutValidationAsyncCallback) => 无效; }' 和 'KnockoutValidationRule' 不兼容:

'(value: any,params: any,callback: KnockoutValidationAsyncCallback) => void' and '{ (value: any,params: 任何):布尔值; (值:任意,参数:任意,回调: KnockoutValidationAsyncCallback): 无效; } 不兼容:

调用签名需要 2 个或更少的参数

我也考虑过将回调设置为可选参数,但这不起作用,因为函数根据签名返回不同的值(没有第三个参数的布尔值,如果存在第三个参数则为无效)。

我在这里做错了什么?我的字符串索引数组的规则有问题吗?是否可以根据这个库的工作原理创建一个 TypeScript 接口?

更新 1

看起来我在KnockoutValidationRule 界面中的重载方面走在了正确的轨道上。我刚刚发现,如果我将 ko.validation.rulesKnockoutValidationRulesArray 更改为 KnockoutValidationRule[],我的测试代码对于同步和异步验证器都可以正常编译...

interface KnockoutValidationStatic {
    //rules: KnockoutValidationRulesArray; // this breaks it
    rules: KnockoutValidationRule[] // this fixes it
    ... other members defined on this interface
}

我是否声明数组错误?

更新 2

这是我用来测试定义的一些示例代码:

/// <reference path="../../ko/knockout-2.2.d.ts" />
/// <reference path="../../ko/knockout.validation.d.ts" />

module TestKoVal {

    ko.validation.rules['test1'] = {
        message: '',
        validator: (value: any, params: any): bool => {
            return false;
        }
    }

    ko.validation.rules['test2'] = {
        async: true,
        message: '',
        validator: function (value: any, params: any, callback: KnockoutValidationAsyncCallback): void => {
            callback(false);
            callback(true);
            callback({ isValid: false, message: 'custom' });
        }
    }
}

就像我说的,当ko.validation.rulesKnockoutValidationRule[] 时,上面的编译很好。当我将其更改为KnockoutValidationRulesArray 时它失败了。

【问题讨论】:

  • 我不是这方面的专家,但请尝试将 KnockoutValidationAsyncCallback 分成两部分(每个签名一个)并在 KnockoutValidationRule 上创建一个额外的重载。因为你在接口上有两个方法,我认为 TypeScript 需要一个有两个方法的对象,而不是一个匹配的函数。
  • @MortenMertner 感谢您的建议。拆分KnockoutValidationAsyncCallback 的问题在于它会阻止代码能够执行回调的两个重载。在验证函数中,我可能想要调用 callback(true)callback({isValid: false, message: 'custom message'})
  • 您能否发布与此相关的课程?我可以稍微摆弄一下,看看能不能想出点什么来。
  • PS:记得把你的 .d.ts 文件发送给维护这个 repo 的人:github.com/borisyankov/DefinitelyTyped
  • @MortenMertner,是的,在我将这个定义文件更加充实之后,我实际上打算向 boris 发送另一个拉取请求。 github.com/borisyankov/DefinitelyTyped/pull/134

标签: typescript knockout-validation


【解决方案1】:

我想我可能已经弄清楚为什么上述方法不起作用了。在 javascript 中,当您使用带有字符串作为索引器的 [] 数组语法时,您并没有创建通常意义上的数组。相反,该语法只是将属性添加到对象。以下是功能等效的:

ko.validation['test1'] = { ... };
ko.validation.test1 = { ... };

【讨论】:

  • 你是对的——这就是 JavaScript 的工作方式——包括 DOM 中的命名元素。
【解决方案2】:

您可以通过修改 KnockoutValidationRule 来解决该问题:

export interface KnockoutValidationRule {
    async?: bool;
    message: string;
    validator: (value: any, params: any, callback?: KnockoutValidationAsyncCallback): bool;
}

并在使用 this 的地方进行相应的更改:

ko.validation.rules['test2'] = {
    async: true,
    message: '',
    validator: (value: any, params: any, callback?: KnockoutValidationAsyncCallback): bool => {
        callback(false);
        callback(true);
        callback({ isValid: false, message: 'custom' });
    }
}

这统一了两个方法签名。验证方法实际上不需要返回 bool,因此声明该方法返回 bool 的事实主要是外观/美学问题。

codeplex site 上围绕这个展开讨论可能是值得的,因为我怀疑这代表 JavaScript 库中不常见的用法。

【讨论】:

  • 外观问题?真的吗?所以你上面的代码真的可以编译,即使它声明了一个 bool 返回类型,但没有返回任何东西?
  • 我同意它不漂亮,可能会误导阅读定义的人,并且仅在您确实可以统一签名的情况下才有效。但它确实编译:)
  • 仅供参考,我放弃了将规则定义作为数组进行字符串索引的尝试,并在问题中使用了与我的代码非常接近的匹配。我把定义文件提交到Boris Yankov的Definite Typed项目,已经拉进master:github.com/borisyankov/DefinitelyTyped/blob/master/…
  • 谢谢!我希望我很快就会享受到你的劳动成果:-)
猜你喜欢
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 2018-01-10
  • 1970-01-01
  • 2016-05-24
相关资源
最近更新 更多