在第 15 行出现 TS 错误,特别是在 e.target.result
中。
参数类型字符串 | ArrayBuffer 不可分配给参数类型字符串类型 ArrayBuffer 不可分配给类型字符串
let fileTag = document.getElementById("filetag"),
preview = document.getElementById("preview");
fileTag.addEventListener("change", function() {
changeImage(this);
});
function changeImage(input) {
let reader;
if (input.files && input.files[0]) {
reader = new FileReader();
reader.onload = function(e) {
preview.setAttribute('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
添加了 HTML
<div class="img-container">
<input type="file" id="filetag">
<img src="" class="profImage" id="preview" alt="profilePic">
</div>
答案 0 :(得分:3)
(独立于实际答案,请考虑使用 URL.createObjectURL
而不是将 File
转换为 data:
URI;它会为您节省一些有关虚假字符串转换的资源。)
问题在于类型检查在本地工作。
let preview = document.getElementById("preview");
let reader = new FileReader();
reader.onload = function(e) {
preview.setAttribute('src', e.target.result);
}
基于周围的上下文,TypeScript 知道 preview
是一个 DOM 节点,因此 preview.setAttribute
需要两个字符串参数。它还知道 e.target
是 FileReader
,因此 its property result
可以是字符串或 ArrayBuffer
。它是哪一个取决于之前在 FileReader
上调用的方法,但此信息很难在类型系统中表达,并且无论如何在事件处理程序中都不可用。类型检查器都知道,事件处理程序可能是在 readAsArrayBuffer
在同一个 FileReader
对象上很远很远的地方被调用之后被调用的。
由于在这种情况下您比类型检查器更了解,您可以使用 type assertion 使其相信该值确实是一个字符串:
reader.onload = function(e) {
preview.setAttribute('src', e.target.result as string);
}
如果您不想在代码中随处放置类型断言,请考虑将您的代码包装在更易于类型检查的抽象中,例如像这样:
function readFileAsDataURL(file): Promise<string> {
return new Promise((accept, reject) => {
const reader = new FileReader();
reader.onload = function (ev) {
accept(ev.target.result as string);
};
/* XXX: rejecting with an event is rather unorthodox */
reader.onabort = reader.onerror = function (ev) {
reject(ev);
}
reader.readAsDataURL(file);
});
}
async function changeImage(input) {
preview.setAttribute('src', await readFileAsDataURL(input.files[0]));
}
现在,如果您记得在代码中的任何地方使用 readFileAsDataURL
而不是直接构造 FileReader
,那么唯一需要类型断言的地方就是该函数内部。
答案 1 :(得分:-1)
你也许可以:
function ab2str(buf: ArrayBuffer): string {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
// ...
reader.readAsDataURL(typeof input.files[0] === 'string' ? input.files[0] : ab2str(input.files[0]))
或者,如果你是肯定的,它总是一个字符串:
reader.readAsDataURL(input.files[0] as string);
基本上如果是字符串就直接使用,但是如果是ArrayBuffer,首先要转换成字符串。不确定打字稿是否能够遵循这一点。
https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
否则,就这样做:
preview.setAttribute('src', e.target.result as string);
再次,假设你是肯定的,它实际上总是一个字符串