-
Notifications
You must be signed in to change notification settings - Fork 282
Description
Describe the bug
csv-parse v6.2.1, sync API, typescript
When supplying an explicit record type to parse<T>, and when using the columns option with function type, the accepted type of columns does not properly resolve to (record: T) => (keyof T)[]. It instead resolves to (record: string[]) => string[] (there are other types in the union, which I've excluded for brevity).
It appears that the intention is for it to resolve to (record: T) => (keyof T)[], given the logic here and here. However, the type arguments are not passed through here. This means that Options["columns"] will always default to T = string[], and thus the ternary linked to yields string.
This can cause TS compile failures if keyof T cannot be trivially coerced to string (e.g. if they're not string, or if they're coming from some other generic type).
To Reproduce
Here is a minimal TS example. The expectation is that it should compile.
test("should compile", () => {
interface Foobar {
1: string;
2: string;
}
const columnMapping = new Map<string, keyof Foobar>([
["col_1", 1],
["col_2", 2],
]);
const records = parse<Foobar>('col_1,col_2\n"foo","bar"', {
columns: (header) =>
header.map((column) => columnMapping.get(column)),
});
expect(records).toEqual([{ 1: "foo", 2: "bar" }]);
});Instead it errors with:
Type '(header: string[]) => (keyof Foobar | undefined)[]' is not assignable to type 'true | ColumnOption<string>[] | ((record: string[]) => ColumnOption<string>[])'.
Type '(header: string[]) => (keyof Foobar | undefined)[]' is not assignable to type '(record: string[]) => ColumnOption<string>[]'.
Type '(keyof Foobar | undefined)[]' is not assignable to type 'ColumnOption<string>[]'.
Type 'keyof Foobar | undefined' is not assignable to type 'ColumnOption<string>'.
Type '1' is not assignable to type 'ColumnOption<string>'.
Workaround
(differs slightly based on the specific scenario)
const records = parse<Foobar>('col_1,col_2\n"foo","bar"', {
columns: (header) =>
header.map((column) => columnMapping.get(column) as undefined),
});