Harry Winser

Async Await Typescript Csv Parser

On far too many occasions I need to parse CSV files to extract the data. I’ve found over the years that also converting them to TypeScript objects is a big help.

I’ve written variations of this code over and over again, and I’m getting annoyed at myself for forgetting / losing previous versions of it. So today, I’m going to share my “janky” yet simple way of parsing a CSV to TypeScript objects.

As with all code on the internet; please make sure you read it and understand it before jamming it into your projects!

The code

import * as fs from "fs";
import * as path from "path";
import { parse } from "csv-parse";

interface ReadCSVOptions {
  columns: string[];
  delemiter: string;
}

const readCSV = async <T>(
  file: string,
  options: ReadCSVOptions,
): Promise<T[]> => {
  const csvFilePath = path.resolve(__dirname, file);
  const fileContent = fs.readFileSync(csvFilePath, { encoding: "utf-8" });
  const csvParser = parse(options);

  return new Promise<T[]>((resolve, reject) => {
    const results: T[] = [];

    csvParser.on("readable", function () {
      let record;
      while ((record = csvParser.read()) !== null) {
        // ignore the row if it equals the same as header
        if (record[options.columns[0]] === options.columns[0]) {
          continue;
        } else {
          results.push(record);
        }
      }
    });

    csvParser.on("error", function (err) {
      reject(err);
    });

    csvParser.on("end", function () {
      resolve(results);
    });

    csvParser.write(fileContent);
    csvParser.end();
  });
};

A few items of note

  1. While I’ve used it personally for little scripts, if you plan to use it for “production” code, PLEASE TEST IT!
  2. I’m aware there are probably npm libraries out there for this exact thing, but I couldn’t find a working one.
  3. It relies on csv-parse - which looks pretty well used and is well supported.
  4. This will load everything into memory. So maybe avoid using for very large CSV files.