75
votes

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

15

15 Answers

74
votes

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 {
76
votes

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
};
37
votes

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;
}
21
votes

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;
17
votes

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

6
votes

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
}
3
votes

Today this worked for me at TypeScript 2.1.1

interface EventTarget { result: any; }
2
votes

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

2
votes

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);
}

1
votes

instead of

    this.localDbRequest.onsuccess = function (event) {
      const db = event.target.result;
    };

do

   this.localDbRequest.onsuccess = function (event) {
     const db = this.result;
   };
1
votes

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

1
votes

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')
};
0
votes

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.

0
votes

Try this.

event.target["result"]
0
votes

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
};