2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

react-papaparse + typescript で results の type が unknown でハマった話

Posted at

現象と結論

Next.js/React.js + TypeScript で、react-papaparse や papaparse を利用すると、Parse 後の戻り値の型が unknown になるため、扱いづらい。というか扱えない。

解決策としては、any を付ける。

検証環境

Next.js + TypeScript

node: v16.13.1
next: 12.0.8
react: 17.0.2
react-papaparse: 4.0.2
(papaparse: 5.3.1)

CSV をパースしたかった

Next.js + TypeScript で、ローカルの CSV をロードして、parse したかった。とある事情により、ファイルのアップロードができなかったので(面倒くさかったので)、input type=fileonChange で直接 parse するようにした。

import { usePapaParse } from 'react-papaparse';
  ...
  const [ csvContent, setCsvContent ] = useState<Array<CsvType>>([]);
  ...
  const onChangeRead = async (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) {
      const csvdata = await e.target.files[0].text();
      readString(csvdata, {
        worker: true,
        complete: (results) => {
          setCsvContent(results.data);
        },
        header: true,
        skipEmptyLines: true,
      });
    }
  };
  ...
  <input type="file" onChange={onChangeRead} />

エラー処理とかはいったん置いといて、こんな感じ。とりあえず動く。なお、react-papaparse は papaparse をラップした UI 系の Module?なので、CSV を読むだけなら papaparse で事足りる。

build できない

yarn dev では動くけど、yarn build はできない。問題はここ。

        complete: (results) => {
          setCsvContent(results.data);
        },
Argument of type 'unknown[]' is not assignable to parameter of type 'SetStateAction<CsvType[]>'.
  Type 'unknown[]' is not assignable to type 'CsvType[]'.
    Type 'unknown' is not assignable to type 'CsvType'.ts

unknown... だと...?

results は、

results = {
  data: [ ... ],    // parsed data
  errors: [ ... ],  // errors encountered
  meta: { ... }     // extra parse info
}

という Object で返ってくる。

results.data は、

(property) ParseResult<unknown>.data: unknown[]
an array of rows. If header is false, rows are arrays; otherwise they are objects of data keyed by the field name.

とあり、CSV の header 有り無しで内容が変わるようだけど、いずれにせよ Array で返ってくる。
unknown だと何にもできないので困る。return して変数に入れれば良い?

readString は、

const readString: <unknown>(csvString: string, config: ParseWorkerConfig<unknown> & {
    download?: false | undefined;
}) => void

void ... 読めるけど、まじ state 書けな〜い。ちょっと詰んだ感。読み込まれる CSV がなにか分からないから unknown なの?そんなバカな!!

コードを当たる。

react-papaparse/src/readString.ts
import PapaParse, { ParseWorkerConfig } from 'papaparse';

export function readString<T>(
  csvString: string,
  config: ParseWorkerConfig<T> & { download?: false | undefined },
) {
  return PapaParse.parse(csvString, config);
}

Generics か。TypeScript が型推論を放棄してるんですね。
React, React + TypeScript, Next, Next + TypeScript の4パターンで確認したところ、TypeScript の場合は、unknown, それ以外は、any で返ってきました。any かぁ...うーん、何だかな。

ここの、readString<T>readString<T = any> であったならば… と思いましたが、本質的でないし、papaparse 本体は、ちょっと読むの面倒だし(ちょっと読んでやめた)、他にも同様の現象が発生してるみたいなので、そっと閉じた。いま忙しい。

というわけで、現時点での解決策。

解決策

どうせ良くて any で返って来るなら、any をこっちで嫌々指定する。complete: (results: any) => {...} ここの部分。

  const [ csvContent, setCsvContent ] = useState<Array<CsvType>>([]);
  ...
  const onChangeRead = async (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) {
      const csvdata = await e.target.files[0].text();
      readString(csvdata, {
        worker: true,
        complete: (results: any) => {
          setCsvContent(results.data);
        },
        header: true,
        skipEmptyLines: true,
      });
    }
  };
  ...
  <input type="file" onChange={onChangeRead} />

tsconfig.json をいじっても動くけど、超絶非推奨なので詳細割愛。

papaparse の場合

CSV を Parse するだけだったら、react-papaparse を使う必要は全くない。react-papaparse は、パースしする際・した後をいい感じにするための module なので、単純に CSV を Parse するだけなら、papaparse 本体を使うべきである。

papaparse なら unknown にならないか?というと、なる。ので、同様に any をつける。

...
import Papa  from 'papaparse';
...
    const results = Papa.parse<any>(csvString, {
      header: true,
    });
    setCsvContent(results.data);
...

おしまい。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?