[英]How do I type a jQuery-like initialization pattern with TypeScript?
I'm using a jQuery-like initialization pattern in my library (I've added a few comments about the types I want these functions to accept and return): 我在我的库中使用类似jQuery的初始化模式(我添加了一些有关我希望这些函数接受并返回的类型的注释):
function JQueryConstructor ( selector /*: string | INSTANCE_OF_JQUERY*/ ) {
if ( selector.__jquery ) return selector;
}
function jQuery ( selector/*: string | INSTANCE_OF_JQUERY*/ )/*: INSTANCE_OF_JQUERY*/ {
return new JQueryConstructor ( selector );
}
const fn = jQuery.fn = jQuery.prototype = JQueryConstructor.prototype = {
constructor: jQuery,
__jquery: true
};
fn.foo = function () {};
jQuery ( '*' ).foo; // => Function
const $mocked = { __jquery: true, foo () {} };
jQuery ( $mocked ) === $mocked; // => true
it works in JavaScript, but how do I write it in TypeScript so that it's properly typed? 它可以在JavaScript中使用,但是如何在TypeScript中编写它以便正确键入?
I have these requirements/problems: 我有以下要求/问题:
new Foo ()
in JavaScript, while TypeScript is complaining that only void functions can be called like that TypeScript应该是JS的超集,但看起来我可以从JavaScript中称为new Foo ()
函数返回任意值,而TypeScript则抱怨只能像这样调用void函数 I couldn't find a way to solve all these problems, can you help me? 我找不到解决所有这些问题的方法,您能帮我吗?
To address your requirements/problems in order: 依次解决您的要求/问题:
Typescript
compliant with the "declaration": true
option 如果我们的代码符合Typescript
的"declaration": true
选项,则可以让编译器执行此操作 new
or to not allow miss matched types. 这样的检查之一是不允许使用new
函数调用任何函数或不允许未命中匹配的类型。 Although you can still emit JS if you have semantic errors (and by default the compiler will do so) it's recommended you fix the errors. 尽管如果您遇到语义错误,仍然可以发出JS(默认情况下编译器会发出),但是建议您修复错误。 My solution to what you want would be to use a class instead of the function JQueryConstructor
and use class-interface merging for extensibility. 我想要的解决方案是使用类而不是函数JQueryConstructor
并使用类接口合并来实现可扩展性。 The result would look something like: 结果如下所示:
class JQuery{
__jquery!: boolean; // Just the declaration
constructor(selector: string | JQuery) {
if(typeof selector !== 'string' && selector.__jquery) return selector;
}
}
JQuery.prototype.__jquery = true;
function foo() { };
interface JQuery {
foo: typeof foo
}
JQuery.prototype.foo = foo;
function jQuery(selector: string | JQuery): JQuery {
return new JQuery(selector);
}
jQuery('*').foo; // => Function
const $mocked = { __jquery: true, foo() { } };
jQuery($mocked) === $mocked; // => true
The minified versions of the code (minified here ) don't differ greatly from yours, Your version is 300bytes, my version compiled to es2015 is 261 bytes and compiled to es5 is 253 bytes (even if I use your longer JQueryConstructor
name it's still 297 bytes). 代码的最小版本( 在此处最小)与您的代码没有太大不同,您的版本为300bytes,我编译为es2015的版本为261字节,编译为es5的版本为253字节(即使我使用更长的JQueryConstructor
名称,它仍为297字节)。 Comparing sizes on such a small example might to be all taht relevant but they seem to be comparable. 在这么小的示例中比较大小可能完全相关,但似乎是可比较的。
Based on the above code the following definition is generated: 根据上面的代码,将生成以下定义:
declare class JQuery {
__jquery: boolean;
constructor(selector: string | JQuery);
}
declare function foo(): void;
interface JQuery {
foo: typeof foo;
}
declare function jQuery(selector: string | JQuery): JQuery;
declare const $mocked: {
__jquery: boolean;
foo(): void;
};
Which will work for any consumers and will allow them to use the same class-interface merging technique to provide extensibility. 它将对任何使用者都有效,并允许他们使用相同的类接口合并技术来提供可扩展性。
Thanks to @titian-cernicova-dragomir I've come up with the following solution, it's somewhat verbose due to having to explicitly define all the interface, but it works: 感谢@ titian-cernicova-dragomir,我提出了以下解决方案,由于必须显式定义所有接口,所以它有些冗长,但是可以使用:
interface jQuery {
constructor: typeof jQueryConstructor,
__jquery: boolean
}
function isJQuery ( x ): x is jQuery {
return x && x['__jquery'];
}
function jQuery ( selector: string | jQuery ): jQuery {
if ( isJQuery ( selector ) ) return selector;
return new jQueryConstructor ( selector );
}
function jQueryConstructor ( selector: string ) {}
const fn = jQuery.fn = jQuery.prototype = jQueryConstructor.prototype = {
constructor: jQueryConstructor,
__jquery: true
} as jQuery;
interface jQuery {
foo ();
}
fn.foo = function () {};
jQuery ( '*' ).foo; // => Function
const $mocked = { __jquery: true, foo () {} } as jQuery;
jQuery ( $mocked ) === $mocked; // => true
jQuery ( '*' ) instanceof jQuery; // => true
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.