在阅读问题How is jQuery's $ a function and an object?
的{{3}}之后,它让我思考。你会如何在打字稿中定义这种类型?
在常规JS中,这是完全有效的:
var f = function() { alert('yo'); }
f.foo = "bar";
alert(f.foo); // alerts "bar"
f(); // alerts "yo"
但是在打字稿中,f.foo
会抛出错误Property 'foo' does not exist on type '() => void'
。
虽然您可以使用this answer获得类似的结果:
var f = function() { alert('yo'); }
f['foo'] = "bar";
alert(f['foo']); // alerts "bar"
f(); // alerts "yo"
这将完全绕过类型系统,以及打字稿的类型安全。
有没有办法在不违反打字稿类型安全的情况下实现此类功能?
答案 0 :(得分:3)
您可以通过在接口上指定调用签名来定义此类型:
interface MyFoo {
(): void;
foo: string;
}
您可以通过将函数转换为any
来初始化对象,然后再将其赋值给变量:
let f: MyFoo = function() { alert('yo'); } as any;
f.foo = 'bar';
x();
另外,JQueryStatic
中的$
类型(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>;
变量的类型)的定义类似:
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Get Directory</title>
<!-- Update your jQuery version??? -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!--
https://cdnjs.com/libraries/crypto-js
-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
<!--[if lt IE 9]>
<script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script> // type="text/javascript" is unnecessary in html5
// Short version of doing `$(document).ready(function(){`
// and safer naming conflicts with $
jQuery(function($) {
$('#file-input').on('change', function() {
// You can't use the same reader for all the files
// var reader = new FileReader
$.each(this.files, function(i, file) {
// Uses different reader for all files
var reader = new FileReader
reader.onload = function() {
// reader.result refer to dataUrl
// theFile is the blob... CryptoJS wants a string...
var encrypted = CryptoJS.AES.encrypt(reader.result, '12334');
var ecr = encrypted.toString();
var blob = new Blob([ecr], {
"type": "text/plain"
});
var link = document.createElement("a");
link.download = "Encrypteddocument";
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
//alert(encrypted);
}
reader.readAsDataURL(file)
$('#thelist').append('FILES: ' + file.name + '<br>')
})
})
});
</script>
</head>
<body>
<input type="file" id="file-input">
<div id="thelist"></div>
<input type="button" id="button" value="Save" />
</body>
</html>
(不能将链接内联,所以在这里)
但是,这并不是真的有用,因为您的问题也是如何使用此类型初始化变量。 JQuery库没有这个问题,因为它没有写在Typescript中。
答案 1 :(得分:1)
您可以使用&
来定义具有多种类型的变量。它被称为“交叉类型”。 official docs中的更多信息。
以下是在您的示例中使用它的方法:
let f: Function & {foo?: String} = function() { alert('yo'); }
f.foo = "bar";
alert(f.foo); // alerts "bar"
f(); // alerts "yo"
此处,f
的类型为Function & {foo?: String}
,因为它既是Function
,也是{foo?: String}
。此处需要?
,因为您只将其初始化为Function
,然后才将值分配给foo
。
您可以在Playground中看到代码编译,甚至提供您开始使用的相同JavaScript代码,验证这是正确的语法。