Search code examples
node.jstypescripttsctypescript3.0

Properly extend stream.Transform class with TypeScript


I have this code:

import * as stream from 'stream';    

export class JSONParser extends stream.Transform {

  lastLineData = '';
  objectMode = true;

  constructor() {
    super();

  }

  transform(chunk, encoding, cb) {

    let data = String(chunk);
    if (this.lastLineData) {
      data = this.lastLineData + data;
    }

    let lines = data.split('\n');
    this.lastLineData = lines.splice(lines.length - 1, 1)[0];

    lines.forEach(l => {
      try {
        // l might be an empty string; ignore if so
        l && this.push(JSON.parse(l));
      }
      catch (err) {
        // noop
      }
    });

    cb();

  }

  flush(cb) {
    if (this.lastLineData) {
      try {
        this.push(JSON.parse(this.lastLineData));
      }
      catch (err) {
        // noop
      }
    }
    this.lastLineData = '';
    cb();
  }


}

the problem is that the TS typings don't recognize the (prototype) methods. Am I extending the Transform class incorrectly?

Here is the problem:

enter image description here

Note that this is correct:

import * as stream from 'stream';

//////////////////////////////////////////////////

export interface IParsedObject {
  [index: string]: any
}

export const createParser = function () {

  let lastLineData = '';

  return new stream.Transform({

    objectMode: true,

    transform(chunk: any, encoding: string, cb: Function) {

      let data = String(chunk);
      if (lastLineData) {
        data = lastLineData + data;
      }

      let lines = data.split('\n');
      lastLineData = lines.splice(lines.length - 1, 1)[0];

      lines.forEach(l => {
        try {
          // l might be an empty string; ignore if so
          l && this.push(JSON.parse(l));
        }
        catch (err) {
          // noop
        }
      });

      cb();

    },

    flush(cb: Function) {
      if (lastLineData) {
        try {
          this.push(JSON.parse(lastLineData));
        }
        catch (err) {
          // noop
        }
      }
      lastLineData = '';
      cb();
    }
  });

};

but that above class does not seem to work the same.


Solution

  • Ok so it seems to work now, I had to pass the constructor options to super(), so it becomes super({objectMode:true}),

    export class JSONParser extends stream.Transform {
    
      lastLineData = '';
    
      constructor() {
        super({objectMode: true});
    
      }
    
      _transform(chunk: any, encoding: string, cb: Function) {
    
        let data = String(chunk);
        if (this.lastLineData) {
          data = this.lastLineData + data;
        }
    
        let lines = data.split('\n');
        this.lastLineData = lines.splice(lines.length - 1, 1)[0];
    
        lines.forEach(l => {
          try {
            // l might be an empty string; ignore if so
            l && this.push(JSON.parse(l));
          }
          catch (err) {
            // noop
          }
        });
    
        cb();
    
      }
    
      flush(cb: Function) {
        if (this.lastLineData) {
          try {
            this.push(JSON.parse(this.lastLineData));
          }
          catch (err) {
            // noop
          }
        }
        this.lastLineData = '';
        cb();
      }
    
      _flush(cb: Function) {
        if (this.lastLineData) {
          try {
            this.push(JSON.parse(this.lastLineData));
          }
          catch (err) {
            // noop
          }
        }
        this.lastLineData = '';
        cb();
      }
    
    }
    

    the only question remaining is whether I should be implementing _flush() or flush(), I am not sure...I implemented both for now...