I am New to typescript. In my Durandal application I migrated to VS-2012 to VS-2015 means typescript 0.9 to typescript 1.8.4. After migrated I got so many build errors. I resolved all those except one. I am getting below build error on types of Events.
ERROR: " Build: Property 'result' does not exist on type 'EventTarget' "
And the code was exactly like this below:
var reader:any,
target:EventTarget;
reader= new FileReader();
reader.onload = function (imgsrc){
var fileUrl = imgsrc.target.result;
}
"Imgsrc" is taking type event.
It's working fine with typescript 0.9 but with 1.8.4 it's throwing error as 'result' does not exist on type 'EventTarget'. Can any one help on this to resolve.
Note: "target:EventTarget" is getting from lib.d.ts
Instead of using event.target.result
, you can just use FileReader.result
.
For example,
const fileReader: FileReader = new FileReader();
fileReader.onload = (event: Event) => {
event.target.result; // This is invalid
fileReader.result; // This is valid
};
While any
is a medicine (almost for anything, but... where is the TypeScript benefit then)... there is a similar issue reported and nice (TypesScript-ish) workaround suggested
Request to change currentTarget in Event interface for lib.d.ts
let me cite:
I ran into this TS2339: Property 'result' does not exist on type 'EventTarget' in JS FileReader onload, and another warning for getSummary() on the event passed to FileReader's onerror. My work-around, to suppress the horrid red squiggily lines;-) is the following: interface FileReaderEventTarget extends EventTarget { result:string } interface FileReaderEvent extends Event { target: FileReaderEventTarget; getMessage():string; } Then in my app: reader.onload = function(fre:FileReaderEvent) { var data = JSON.parse(fre.target.result); ... }
And, until some change in lib.d.ts, we still do work with known interface
EDIT Dec 2019:
With this fix, you might be getting
error TS2322: Type '(this: FileReader, e: FileReaderEvent) => void' is not assignable to type '(this: FileReader, ev: ProgressEvent) => any'.
If so, just replace
interface FileReaderEvent extends Event {
with
interface FileReaderEvent extends ProgressEvent {
With my old type script the parameter "imgsrc" is having any type by default.
So, now I made it as (imgsrc:any). It's working fine.
var reader:any,
target:EventTarget;
reader= new FileReader();
reader.onload = function (imgsrc:any){
var fileUrl = imgsrc.target.result;
}
The issue is with the typescript definitions. A simple cheat is:
let target: any = e.target; //<-- This (any) will tell compiler to shut up!
let content: string = target.result;
Just let TypScript know what type you would expect it to be.
Here is the fix:
let reader = new FileReader();
reader.onload = function (event){
let fileUrl = (<FileReader>event.target).result;
}
You could also use reader.result
instead in this case
If anyone is finding the simplest solution then this worked for me.
var reader:any,
target:EventTarget;
reader= new FileReader();
reader.onload = function (imgsrc){
//var fileUrl = imgsrc.target.result; //change to
var fileUrl = (imgsrc.target as FileReader).result; //cast to correct type
}
Today this worked for me at TypeScript 2.1.1
interface EventTarget { result: any; }
If this error comes Type 'string | ArrayBuffer' is not assignable to type 'string'. Type 'ArrayBuffer' is not assignable to type 'string'
fileReader.result+' ';//valid fileReader.result; //invalid
I had the same issue in angular with a FileReader
.
The solution is rather simple (Typescript has the necessary type). You have to use ProgressEvent<FileReader>
. It can be found im lib.dom.d.ts
in the typescript installation, so it should be globally availabe if you build with
lib: {
"dom"
}
in your tsconfig.json
.
Here is the code where i had to use it:
function read(file: File) {
const fileReader = new FileReader();
fileReader.onloadend = function (e: ProgressEvent<FileReader>) {
const arr = (new Uint8Array(parseInt(e.target.result.toString(), 10))).subarray(0, 4);
var header = "";
for (var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
console.log(header);
// Check the file signature against known types
};
fileReader.readAsArrayBuffer(file);
}
instead of
this.localDbRequest.onsuccess = function (event) {
const db = event.target.result;
};
do
this.localDbRequest.onsuccess = function (event) {
const db = this.result;
};
The target object can be accessed as below to prevent error until fix:
reader= new FileReader();
reader.onload = function (imgsrc){
var fileUrl = imgsrc.target["result"];
}
Treating the target as a Javascript Object
The above solutions didn't fit my similar issue with IndexedDB so I thought I'd share what did work in my scenario. By changing the (event)
functions' arguments to (event: any)
I was able to ignore the type errors.
Sample Code:
let request = window.indexedDB.open('userChannels', 3);
request.onerror = function(event: any ) {
console.log('ERROR: Failed to create userChannels local DB' + event.target.errorCode)
};
request.onsuccess = function(event: any) {
let db = event.target.result;
console.log('SUCCESS: Created userChannels local DB')
};
After lib.dom.d.ts analyzation it is simple:
const fileReader: FileReader = new FileReader();
fileReader.onload = (event: ProgressEvent<FileReader>) => {
event.target.result; // This is valid
};
this is a break change of javascript/typescript.
what you will need to do is to just replace "event.target.result" by "this.result".
"this" here refers to the context of interface "MSBaseReader".
below are my implementation excerpt:
let reader = new FileReader();
let profile: TransProfile = new TransProfile();
reader.onload = function(event){
profile.avatar = new Uint8Array(this.result);
}
reader.onerror = function(event){
}
this.photoLib.getPhoto(item)
.then(blob => reader.readAsArrayBuffer(blob))
.then(() => this.doUpload(profile));
"MSBaseReader" interface definition:
interface MSBaseReader {
onabort: (this: MSBaseReader, ev: Event) => any;
onerror: (this: MSBaseReader, ev: ErrorEvent) => any;
onload: (this: MSBaseReader, ev: Event) => any;
onloadend: (this: MSBaseReader, ev: ProgressEvent) => any;
onloadstart: (this: MSBaseReader, ev: Event) => any;
onprogress: (this: MSBaseReader, ev: ProgressEvent) => any;
readonly readyState: number;
readonly result: any;
abort(): void;
readonly DONE: number;
readonly EMPTY: number;
readonly LOADING: number;
addEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
"FileReader" interface definition
interface FileReader extends EventTarget, MSBaseReader {
readonly error: DOMError;
readAsArrayBuffer(blob: Blob): void;
readAsBinaryString(blob: Blob): void;
readAsDataURL(blob: Blob): void;
readAsText(blob: Blob, encoding?: string): void;
addEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
also note that, due to the context change of "this" within "onload()", your class-based definitions are not accessible within "reader.onload = function(event){..."; meaning you can not use "this.class-property" style to address your class properties.
you will have to define local variable. see the definition and usage of "profile" in above excerpt.
Try this.
event.target["result"]
Success story sharing
Type 'string | ArrayBuffer' is not assignable to type 'string'. Type 'ArrayBuffer' is not assignable to type 'string'
> fileReader.result;+'';
ProgressEvent<FileReader>
and not justEvent
...