参数类型字符串 | ArrayBuffer 不可分配给参数类型 string

时间:2021-03-25 20:48:39

标签: typescript filereader

在第 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>

2 个答案:

答案 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.targetFileReader,因此 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);

再次,假设你是肯定的,它实际上总是一个字符串