Polyfills,Shims& TypeScript扩展

时间:2013-12-23 13:01:36

标签: javascript typescript polyfills

在我继续提问之前,请允许我指出我已经对这个主题做了大量研究,并且已经提出了几个相关的问题,你可以在这里找到:

Extending Object.prototype with TypeScript

Extending instance/static functions on existing prototypes with TypeScript

虽然TypeScript在1.0版本的道路上似乎已经相当成熟,但我很早就注意到,在它的婴儿时期,填充/垫片/猴子并不容易使用TypeScript修补/扩展核心对象(对象,字符串,数字,布尔等)的功能...但是这在纯JavaScript中是完全合法的,在我看来,这对于创建跨浏览器兼容和兼容的API是必要的。

现在我们已经使用0.9.5版了,我注意到这个领域有很多改进,我们现在可以扩展核心对象的原型了,看起来我们也可以为核心对象添加静态函数......但是......这似乎是错误的!

请考虑以下代码示例:

interface Object {
    /********************************/
    /*  Static functions            */
    /********************************/

    // ECMAScript 6 Object.is function
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
    is(v1: any, v2: any): boolean;

    /********************************/
    /*  Prototype functions         */
    /********************************/

    // Custom method for testing obejct equality (based on Java / C# principles)
    equals(obj: any): boolean;
}

// Object.is polyfill
(() => {
    if(!Object.is) {
        Object.is = function(v1: any, v2: any): boolean {
            if (v1 === 0 && v2 === 0) {
                return 1 / v1 === 1 / v2;
            }
            if (v1 !== v1) {
                return v2 !== v2;
            }
            return v1 === v2;
        }
    }
})();

// Object.prototype.equals implementation
Object.prototype.equals = function(obj: any): boolean {
    return Object.is(obj, this);
}

想玩吗?... Playground

您可能已经注意到这里的错误...接口不应包含静态函数的定义,只应包含应绑定到原型的定义。在这方面,如果您查看lib.d.ts,您将看到静态函数的声明方式不同:

declare var Object: {
    new (value?: any): Object;
    (): any;
    (value: any): any;
    prototype: Object;
    getPrototypeOf(o: any): any;
    getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor;
    getOwnPropertyNames(o: any): string[];
    create(o: any, properties?: PropertyDescriptorMap): any;
    defineProperty(o: any, p: string, attributes: PropertyDescriptor): any;
    defineProperties(o: any, properties: PropertyDescriptorMap): any;
    seal(o: any): any;
    freeze(o: any): any;
    preventExtensions(o: any): any;
    isSealed(o: any): bool;
    isFrozen(o: any): bool;
    isExtensible(o: any): bool;
    keys(o: any): string[];
}

这意味着我们应该在声明中添加is(v1: any, v2: any): boolean; ...但TypeScript中的声明不像接口那样是开放式的,因此这是不可能的。

话虽如此,如果我从界面中删除声明,那么TypeScript会抱怨Object.is不存在......所以看来我必须让它在那里让polyfill工作!< / p>

&#34;如果它有效......那么问题是什么?&#34; - 是的它有效,但只是因为它无论如何都不优雅。

因为is已经静态实现,但它是作为Object的一部分签约的,TypeScript intellisense仍然期待Object.prototype.is并且不会识别Object.is的存在

我觉得我现在正在胡扯,所以我会明白这一点。

  1. 这是一个已知问题吗?
  2. 我错过了什么吗?
  3. 正在筹备什么来纠正这个问题?
  4. 注意:我刚刚注意到,您现在似乎可以覆盖声明,因此您可以通过完全覆盖声明来添加is(v1: any, v2: any): boolean; ...但是我仍觉得这不是最优雅的解决方案。

1 个答案:

答案 0 :(得分:2)

提出了这个问题。不命名Object var类型的主要原因是我们想要避免使用一个名称(你会怎么称呼它?),并且这将使将来更难以转换它键入类形状而不会导致重大变化。

您最好的解决方案是为您的项目提供自定义的lib.d.ts;只要编译器可以找到一些具有基本类型(Number,String等)名称的类型,实际上lib.d.ts的内容并不重要。所以你可以有例如lib-es6.d.ts将新成员直接添加到这些匿名类型,或者例如lib-extensible.d.ts将匿名类型更改为命名接口,因此您可以在其他地方的polyfill定义文件中扩展它们。