Skip to content

Commit 2024c2d

Browse files
committed
feat(csv-parse): add generic type argument
This is based on the columns option. When falsy, the records are string[][]. When defined, the records are T[], T defaulting to unknown. Fix #407
1 parent c40c0d2 commit 2024c2d

File tree

4 files changed

+90
-38
lines changed

4 files changed

+90
-38
lines changed

packages/csv-parse/lib/index.d.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import * as stream from "stream";
66

7-
export type Callback = (err: CsvError | undefined, records: any | undefined, info: Info) => void;
7+
export type Callback<T = unknown> = (err: CsvError | undefined, records: T[] | undefined, info?: Info) => void;
88

99
export interface Parser extends stream.Transform {}
1010

@@ -274,10 +274,18 @@ export class CsvError extends Error {
274274
constructor(code: CsvErrorCode, message: string | string[], options?: Options, ...contexts: any[]);
275275
}
276276

277-
declare function parse(input: Buffer | string, options?: Options, callback?: Callback): Parser;
278-
declare function parse(input: Buffer | string, callback?: Callback): Parser;
279-
declare function parse(options?: Options, callback?: Callback): Parser;
280-
declare function parse(callback?: Callback): Parser;
277+
type OptionsWithColumns = Omit<Options, 'columns'> & {
278+
columns: Exclude<Options['columns'], undefined | false>
279+
}
280+
281+
declare function parse<T = unknown>(input: string | Buffer, options: OptionsWithColumns, callback?: Callback<T>): Parser;
282+
declare function parse<T = unknown>(input: string | Buffer, options: Options, callback?: Callback<string[]>): Parser;
283+
284+
declare function parse<T = unknown>(options: OptionsWithColumns, callback?: Callback<T>): Parser;
285+
declare function parse<T = unknown>(options: Options, callback?: Callback<string[]>): Parser;
286+
287+
declare function parse(input: string | Buffer, callback?: Callback<string[]>): Parser;
288+
declare function parse(callback?: Callback<string[]>): Parser;
281289

282290
// export default parse;
283291
export { parse }

packages/csv-parse/lib/sync.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11

22
import { Options } from './index.js';
33

4-
declare function parse(input: Buffer | string, options?: Options): any;
4+
type OptionsWithColumns = Omit<Options, 'columns'> & {
5+
columns: Exclude<Options['columns'], undefined | false>
6+
}
7+
8+
declare function parse<T = unknown>(input: Buffer | string, options: OptionsWithColumns): T[];
9+
declare function parse(input: Buffer | string, options: Options): string[][];
10+
declare function parse(input: Buffer | string): string[][];
11+
512
// export default parse;
613
export { parse };
714

packages/csv-parse/test/api.types.sync.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@ import {
66
ColumnOption, Options, Info, CsvErrorCode, CsvError
77
} from '../lib/sync.js'
88

9-
describe('API Types', () => {
9+
describe('API Types - Sync', () => {
1010

1111
it('respect parse signature', () => {
1212
// No argument
1313
parse("")
1414
parse("", {})
1515
parse(Buffer.from(""))
1616
parse(Buffer.from(""), {})
17+
parse(Buffer.from(""), {columns: true})
1718
})
1819

1920
it('return records', () => {
2021
try {
21-
const records: object = parse("")
22+
const records = parse("")
2223
typeof records
2324
}catch (err){
2425
if (err instanceof CsvError){
@@ -89,5 +90,31 @@ describe('API Types', () => {
8990
};
9091
return info;
9192
})
92-
93+
94+
describe('Generic types', () => {
95+
it('Exposes string[][] if columns is not specified', () => {
96+
const data: string[][] = parse("", {})
97+
})
98+
99+
it('Exposes string[][] if columns is falsy', () => {
100+
const data: string[][] = parse("", {
101+
columns: false
102+
})
103+
})
104+
105+
it('Exposes unknown[] if columns is specified as boolean', () => {
106+
const data: unknown[] = parse("", {
107+
columns: true
108+
})
109+
})
110+
111+
it('Exposes T[] if columns is specified', () => {
112+
type Person = {name: string, age: number}
113+
114+
const data: Person[] = parse<Person>("", {
115+
columns: true
116+
})
117+
})
118+
})
119+
93120
})

packages/csv-parse/test/api.types.ts

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

22
import 'should'
33
import { parse, CastingContext, Info, Options, Parser, CsvError } from '../lib/index.js'
4-
import { parse as parse_sync } from '../lib/sync.js'
54

65
describe('API Types', () => {
76

@@ -52,40 +51,16 @@ describe('API Types', () => {
5251
})
5352

5453
it('Receive Callback', (next) => {
55-
parse('a\nb', function(err: Error|undefined, records: object, info: Info){
54+
parse('a\nb', function(err, records, info){
5655
if(err !== undefined){
57-
records.should.eql([['a'], ['b']])
58-
info.records.should.eql(2)
56+
records!.should.eql([['a'], ['b']])
57+
info!.records.should.eql(2)
5958
}
6059
next(err)
6160
})
6261
})
63-
64-
})
65-
66-
describe('sync api', () => {
67-
68-
it('respect parse signature', () => {
69-
// No argument
70-
parse_sync("")
71-
parse_sync("", {})
72-
parse_sync(Buffer.from(""))
73-
parse_sync(Buffer.from(""), {})
74-
})
75-
76-
it('return records', () => {
77-
try {
78-
const records: object = parse_sync("")
79-
typeof records
80-
}catch (err){
81-
if (err instanceof CsvError){
82-
err.message
83-
}
84-
}
85-
})
86-
8762
})
88-
63+
8964
describe('Info', () => {
9065

9166
const fakeinfo = {
@@ -395,4 +370,39 @@ describe('API Types', () => {
395370
})
396371
})
397372
})
373+
374+
describe('Generic types', () => {
375+
it('Exposes string[][] if columns is not specified', (next) => {
376+
parse("", {}, (error, records: string[][] | undefined) => {
377+
next(error)
378+
})
379+
})
380+
381+
it('Exposes string[][] if columns is falsy', (next) => {
382+
parse("", {
383+
columns: false
384+
}, (error, records: string[][] | undefined) => {
385+
next(error)
386+
})
387+
})
388+
389+
it('Exposes unknown[] if columns is specified as boolean', (next) => {
390+
parse("", {
391+
columns: true
392+
}, (error, records: unknown[] | undefined) => {
393+
next(error)
394+
})
395+
})
396+
397+
it('Exposes T[] if columns is specified', (next) => {
398+
type Person = {name: string, age: number}
399+
400+
parse<Person>("", {
401+
columns: true
402+
}, (error, records: Person[] | undefined) => {
403+
next(error)
404+
})
405+
})
406+
})
407+
398408
})

0 commit comments

Comments
 (0)