(Irrespective of the actual solution, it is worth considering utilizing URL.createObjectURL instead of changing the File to a data: URI; this approach can help conserve resources by avoiding unnecessary string conversions.)
The issue arises from the fact that type checking operates at a local level.
let preview = document.getElementById("preview");
let reader = new FileReader();
reader.onload = function(e) {
preview.setAttribute('src', e.target.result);
}
Based on the surrounding context, TypeScript understands that preview is a DOM element, and therefore expects two string arguments for preview.setAttribute. It also recognizes that e.target is a FileReader
, which means its property result could be either a string or an ArrayBuffer. The specific type depends on the method previously called on the FileReader, but conveying this information in a type system is complex and unavailable within the event handler. For all TypeScript knows, the event handler might have been triggered after readAsArrayBuffer was executed somewhere distant on the same FileReader object.
Given your superior understanding compared to the type checker, you can utilize a type assertion to confirm that the value is indeed a string:
reader.onload = function(e) {
preview.setAttribute('src', e.target.result as string);
}
If you prefer not to clutter your code with numerous type assertions, consider encapsulating your code in a more easily typed abstraction, like so:
function readFileAsDataURL(file): Promise<string> {
return new Promise((accept, reject) => {
const reader = new FileReader();
reader.onload = function (ev) {
accept(ev.target.result as string);
};
/* Note: rejecting with an event is uncommon */
reader.onabort = reader.onerror = function (ev) {
reject(ev);
}
reader.readAsDataURL(file);
});
}
async function changeImage(input) {
preview.setAttribute('src', await readFileAsDataURL(input.files[0]));
}
By consistently using readFileAsDataURL throughout your code instead of directly creating FileReader instances, the need for a type assertion will only exist within that single function.