2016-09-23 103 views
1

的NPM包csv-parse实现的Node.js流等API:如何在TypeScript中声明一个类似Stream的接口?

const parser = parse(); 
parser.on('readable',() => { 
    let record: any; // <-- it should be string[] 
    while (record = parser.read()) { 
    output.push(record); 
    } 
}); 

及其type declaration是:

interface parse { 
    (options?: options): NodeJS.ReadWriteStream; 
} 

parse返回类型是NodeJS.ReadWriteStream,其具有方法read返回string | Buffer

interface ReadWriteStream extends ReadableStream, WritableStream { 
    // ... 
} 

interface ReadableStream extends EventEmitter { 
    read(size?: number): string | Buffer; 
    // ... 
} 

根据这个定义,我不能定义变量let record: any = parser.read()其实际类型string[]

我试图修改的类型定义的CSV解析如下:

interface ParserStream extends NodeJS.ReadWriteStream { 
    read(size?: number): string[];  
} 

interface parse { 
    (options?: options): ParserStream; 
} 

它不起作用,因为打字稿不允许扩展接口和变革方法的返回类型。

我能想到的是的NodeJS流更改为通用型,如:

interface GenericReadableStream <T> extends EventEmitter { 
    read(size?: number): T 
    // ... 
} 

interface ReadableStream extends GenericReadableStream <string | Buffer> {} 

然后我可以定义:

interface ParserStream extends GenericReadableStream <string[]> {} 

我不知道这是否是一个很好的方式。它在当前的Node.JS类型定义中影响很大。

回答

1

首先,CsvParser实现使用object mode中的流量,因此string | Buffer对于CsvParser.read并不是一个很好的返回类型。

幸运的是,TypeScript允许扩展接口并将方法的返回类型更改为any。所以,你可以改变csv-parse类型定义

interface CsvParser extends NodeJS.ReadWriteStream { 
     read(size?: number): any; 

让这个代码编译

let record: string[]; 
while (record = parser.read()) { 

但这是不够严谨的,因为这将编译过:

let record: number[]; 
while (record = parser.read()) { 

要禁止的是,您不知何故需要声明一个将read返回类型更改为string[]的接口。由于string[]string | Buffer不兼容,因此您无法在直接扩展ReadWriteStream的界面中执行此操作。但是,如果您添加中间步骤(可扩展ReadWriteStream并且返回类型与read兼容),则可能会出现这种情况。它可以是any路口类型和所需类型,我们可以使用泛型参数T

interface ObjectStream<T> extends NodeJS.ReadWriteStream { 
    read(size?: number): any & T; 
} 

然后你就可以有CsvParser扩展它:

interface CsvParser extends ObjectStream<string[]> { 
    read(size?: number): string[]; 
} 

这样的话,你仍然需要修改csv-parser类型定义,但不需要更改节点流的类型定义。

注意:在回答第一个尝试是

interface CsvParser extends NodeJS.ReadWriteStream { 
     read(size?: number): any & string[]; 

,正如@aleung注意到,没有从

interface CsvParser extends NodeJS.ReadWriteStream { 
     read(size?: number): any; 

不同,因为它仍然允许指定的阅读方式的结果任何类型的变量。

+1

我在TypeScript 2.0.3上测试过。 'any'和'string []'的交互作用是'any'。所以它仍然可以分配给'number []'。 – aleung

+0

哦,是的,我简化了答案,没有检查。在ReadWriteStream和CsvParser之间需要一个中间接口,在其中重写'read'来返回'any&string []',然后在CsvParser中,您可以重写它以仅返回'string []'。我会再次检查并更新答案。 – artem

+0

我更新了答案 - 我认为它现在应该可以工作 – artem