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

## 現象と結論
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=file``` を ```onChange``` で直接 parse するようにした。

```typescript
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``` はできない。問題はここ。

```typescript
        complete: (results) => {
          setCsvContent(results.data);
        },
```

```typescript
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``` は、

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

という ```Object``` で返ってくる。

```results.data``` は、

```typescript
(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``` は、

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

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

コードを当たる。

```typescript: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) => {...}``` ここの部分。

```typescript
  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``` をつける。


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

おしまい。