如何在TypeScript中声明类似Stream的界面?

时间:2016-09-23 15:29:45

标签: typescript typescript-typings

npm包csv-parse实现了一个类似API的Node.JS 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-parse的类型定义:

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

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

它不起作用,因为TypeScript不允许扩展接口并更改方法的返回类型。

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

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

interface ReadableStream extends GenericReadableStream <string | Buffer> {}

然后我可以定义:

interface ParserStream extends GenericReadableStream <string[]> {}

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

1 个答案:

答案 0 :(得分:1)

首先,CsvParser实施使用object mode中的流,因此string | BufferCsvParser.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[]的接口。您无法在直接扩展ReadWriteStream的界面中执行该操作,因为string[]string | Buffer不兼容。但是,如果添加中间步骤 - 扩展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;

因为它仍然允许将读取结果分配给任何类型的变量。