After reading this answer to the question How is jQuery's $ a function and an object?, it got me thinking. How would you define this kind of type in typescript?
In regular JS this is completely valid:
var f = function() { alert('yo'); }
f.foo = "bar";
alert(f.foo); // alerts "bar"
f(); // alerts "yo"
However in typescript, f.foo would throw an error, Property 'foo' does not exist on type '() => void'.
While you could achieve a similar result using bracket notation:
var f = function() { alert('yo'); }
f['foo'] = "bar";
alert(f['foo']); // alerts "bar"
f(); // alerts "yo"
This would entirely bypass the type system, and there for the type safety, of typescript.
Is there a way of implementing this type of functionality without violating the type safety of typescript?
You can define this kind of type by specifying an invocation signature on an interface:
interface MyFoo {
(): void;
foo: string;
}
And you can initialize the object by casting the function to any before assigning it to the variable:
let f: MyFoo = function() { alert('yo'); } as any;
f.foo = 'bar';
x();
Playground link
As an aside, the JQueryStatic type (which is the type of the $ variable) is defined similarly in the JQuery defintions:
interface JQueryStatic<TElement extends Node = HTMLElement> {
...
Deferred: JQuery.DeferredStatic;
...
(html: JQuery.htmlString, ownerDocument_attributes: Document | JQuery.PlainObject): JQuery<TElement>;
...
(selector: JQuery.Selector, context: Element | Document | JQuery | undefined): JQuery<TElement>;
(Can't put the links inline, so here they are)
However, this doesn't really help, as your question is also how to initialize a variable with this type. The JQuery library doesn't have that problem, because it isn't written in Typescript.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With