你能在 TypeScript 中扩展一个函数吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38338013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:39:12  来源:igfitidea点击:

Can you extend a function in TypeScript?

typescript

提问by Will Munn

I help maintain a JavaScript library that produces spy functions which allow you to inspect how a passed-in function was called (mainly for use in unit testing).

我帮助维护一个 JavaScript 库,该库生成间谍函数,允许您检查传入函数的调用方式(主要用于单元测试)。

The library creates a function that has additional properties on it that allow you to inspect the calls.

该库创建了一个函数,该函数具有允许您检查调用的附加属性。

Is it possible to create a TypeScript definition that will allow the function to be passed in to methods that require a function AND have extra properties?

是否可以创建一个 TypeScript 定义,允许将函数传递给需要函数并具有额外属性的方法?

This is invalid, but something like:

这是无效的,但类似于:

class Spy extends function {
    wasCalled: () => boolean;
    ...
}

Which would allow me to pass a spy into a function with this signature:

这将允许我将间谍传递到具有此签名的函数中:

function subjectUnderTest(callback:() => void) {
    ...
}

回答by Mattias Buelens

Yes, the TypeScript handbook calls this a "hybrid type", because it's a combination of a function type and a regular interface.

是的,TypeScript 手册将其称为“混合类型”,因为它是函数类型和常规接口的组合。

interface Spy {
    (foo: string, bar: number) : boolean; // Just an example
    wasCalled() : boolean;
}

var spy : Spy = createASpySomehow();
var result = spy("foo", 123);
if (spy.wasCalled()) {
    // ...
}

回答by nalply

I wanted to extend a class with a function, too, and worked out a TypeScript-only solution. I am not really sure whether this is a good idea because clever solutions are not always good solutions. YMMV.

我也想用一个函数扩展一个类,并制定了一个仅限 TypeScript 的解决方案。我不确定这是否是一个好主意,因为聪明的解决方案并不总是好的解决方案。天啊。

Thanks to Mattias Buelens to provide a partial answer! I am building on it.

感谢 Mattias Buelens 提供部分答案!我正在建立它。

// same as in the answer of Mattias
interface Spy {
    (foo: string, bar: number): boolean // Just an example
    wasCalled(): boolean
}

// and now for the real solution!
class Spy {
    _wasCalled: boolean
    _baz: boolean // Just an example

    private constructor(baz: boolean) {
        this._wasCalled = false
        this._baz = baz
    }

    wasCalled(): boolean {
        return this._wasCalled
    }

    toString() { return '[object Spy]' }

    static create(baz: boolean) {
        const f = <Spy>function(this: Spy, foo: string, bar: number): boolean {
            // Do your thing here. Use f instead of this!
            console.log('wasCalled', f.wasCalled())
            f._wasCalled = true
        }
        const spy = new Spy(baz)
        Object.assign(f, spy)
        Object.setPrototypeOf(f, Spy.prototype)

        return f
    }
}

The idea is to create a function and the instance of Spy, then assign both the prototype and the properties to the function. Return the instance from a static method. A bonus is the toString()method.

这个想法是创建一个函数和 的实例Spy,然后将原型和属性分配给函数。从静态方法返回实例。奖金是toString()方法。

const spy = Spy.create(true)
console.log('calling spy', spy('foo', 42))
console.log('instanceof', spy instanceof Spy)

works as expected.

按预期工作。

I don't think that new Spy()would work because we need to assign to a function not the other way round. And because we can't replace thiswe can't make thisa callable. A hypothetical way I see is to extend a class with really a function constructor somehow like this: class Spy2 extends function() {} {}, but I didn't find a way to get this working.

我认为这new Spy()行不通,因为我们需要分配给一个函数,而不是相反。而且因为我们不能替换,所以this我们不能做this一个可调用的。我看到的一种假设方法是使用真正的函数构造函数扩展一个类,就像这样: class Spy2 extends function() {} {},但我没有找到让它工作的方法。