Typescript:有没有更好的方法来获取类型化流?

Typescript:有没有更好的方法来获取类型化流?,typescript,generics,stream,typescript-typings,Typescript,Generics,Stream,Typescript Typings,对象流很好,但它们目前是非类型化的,这意味着您可以将无意义的流连接在一起。嘘 目标(ish) 所以,这里有更好的方法 首先,定义(代码库中的某个地方)一个JS文件,该文件只需重新导出相应的流类: // Readable.js export { Readable } from 'stream'; 然后创建一个附带的.d.ts文件,并编写您想要的任何类型定义。这是我的,大部分是忠实地从@types/node/index.d.ts复制的 // Readable.d.ts import { Basic

对象流很好,但它们目前是非类型化的,这意味着您可以将无意义的流连接在一起。嘘

目标(ish)


所以,这里有更好的方法

首先,定义(代码库中的某个地方)一个JS文件,该文件只需重新导出相应的流类:

// Readable.js
export { Readable } from 'stream';
然后创建一个附带的
.d.ts
文件,并编写您想要的任何类型定义。这是我的,大部分是忠实地从
@types/node/index.d.ts
复制的

// Readable.d.ts
import { BasicCallback } from './core';

export interface Readable<T> extends ReadStream<T> {}
export class Readable<T> {
  constructor(opts?: ReadableOptions<Readable<T>>);

  _read?(size: number): void;
  _destroy?(error: Error | null, callback: BasicCallback): void;
}

export interface ReadStream<T> {
  readable: boolean;
  readonly readableHighWaterMark: number;
  readonly readableLength: number;
  read(size?: number): T;
  setEncoding(encoding: string): this;
  pause(): this;
  resume(): this;
  isPaused(): boolean;
  unpipe<T extends NodeJS.WritableStream>(destination?: T): this;
  unshift(chunk: T): void;
  wrap(oldStream: NodeJS.ReadableStream): this;
  push(chunk: T | null, encoding?: string): boolean;
  destroy(error?: Error): void;

  /**
   * Event emitter
   * The defined events on documents including:
   * 1. close
   * 2. data
   * 3. end
   * 4. readable
   * 5. error
   */
  addListener(event: 'close', listener: () => void): this;
  addListener(event: 'data', listener: (chunk: T) => void): this;
  addListener(event: 'end', listener: () => void): this;
  addListener(event: 'readable', listener: () => void): this;
  addListener(event: 'error', listener: (err: Error) => void): this;
  addListener(event: string | symbol, listener: (...args: any[]) => void): this;

  emit(event: 'close'): boolean;
  emit(event: 'data', chunk: T): boolean;
  emit(event: 'end'): boolean;
  emit(event: 'readable'): boolean;
  emit(event: 'error', err: Error): boolean;
  emit(event: string | symbol, ...args: any[]): boolean;

  on(event: 'close', listener: () => void): this;
  on(event: 'data', listener: (chunk: T) => void): this;
  on(event: 'end', listener: () => void): this;
  on(event: 'readable', listener: () => void): this;
  on(event: 'error', listener: (err: Error) => void): this;
  on(event: string | symbol, listener: (...args: any[]) => void): this;

  once(event: 'close', listener: () => void): this;
  once(event: 'data', listener: (chunk: T) => void): this;
  once(event: 'end', listener: () => void): this;
  once(event: 'readable', listener: () => void): this;
  once(event: 'error', listener: (err: Error) => void): this;
  once(event: string | symbol, listener: (...args: any[]) => void): this;

  prependListener(event: 'close', listener: () => void): this;
  prependListener(event: 'data', listener: (chunk: T) => void): this;
  prependListener(event: 'end', listener: () => void): this;
  prependListener(event: 'readable', listener: () => void): this;
  prependListener(event: 'error', listener: (err: Error) => void): this;
  prependListener(event: string | symbol, listener: (...args: any[]) => void): this;

  prependOnceListener(event: 'close', listener: () => void): this;
  prependOnceListener(event: 'data', listener: (chunk: T) => void): this;
  prependOnceListener(event: 'end', listener: () => void): this;
  prependOnceListener(event: 'readable', listener: () => void): this;
  prependOnceListener(event: 'error', listener: (err: Error) => void): this;
  prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;

  removeListener(event: 'close', listener: () => void): this;
  removeListener(event: 'data', listener: (chunk: T) => void): this;
  removeListener(event: 'end', listener: () => void): this;
  removeListener(event: 'readable', listener: () => void): this;
  removeListener(event: 'error', listener: (err: Error) => void): this;
  removeListener(event: string | symbol, listener: (...args: any[]) => void): this;

  [Symbol.asyncIterator](): AsyncIterableIterator<T>;
}

export interface ReadableOptions<This> {
  highWaterMark?: number;
  encoding?: string;
  objectMode?: boolean;
  read?(this: This, size: number): void;
  destroy?(
      this: This,
      error: Error | null,
      callback: BasicCallback,
      ): void;
}
//Readable.d.ts
从“/core”导入{BasicCallback};
导出接口可读扩展ReadStream{}
导出类可读{
构造函数(选项?:可读选项);
_读取?(大小:编号):无效;
_销毁?(错误:错误| null,回调:BasicCallback):无效;
}
导出接口读流{
可读:布尔;
readonly readableHighWaterMark:数字;
readonly readableLength:数字;
读数(尺寸?:数字):T;
setEncoding(encoding:string):这个;
暂停():这个;
resume():这个;
isPaused():布尔值;
取消管道(目的地?:T):此;
unshift(chunk:T):void;
wrap(oldStream:NodeJS.ReadableStream):这个;
push(chunk:T | null,编码?:字符串):布尔值;
销毁(错误?:错误):无效;
/**
*事件发射器
*文档上定义的事件包括:
*1.关闭
*2.数据
*3.结束
*4.可读性
*5.错误
*/
addListener(事件:'close',侦听器:()=>void):这个;
addListener(事件:“数据”,侦听器:(chunk:T)=>void):这个;
addListener(事件:'end',侦听器:()=>void):这个;
addListener(事件:“可读”,侦听器:()=>void):此;
addListener(事件:'error',侦听器:(err:error)=>void):此;
addListener(事件:字符串|符号,侦听器:(…args:any[])=>void):此;
发射(事件:“关闭”):布尔值;
emit(事件:'data',块:T):布尔值;
发射(事件:“结束”):布尔值;
发出(事件:“可读”):布尔值;
发出(事件:“错误”,错误:错误):布尔值;
emit(事件:string | symbol,…args:any[]):布尔值;
on(事件:'close',侦听器:()=>void):此;
on(event:'data',listener:(chunk:T)=>void):this;
on(事件:'end',侦听器:()=>void):此;
on(事件:'readable',侦听器:()=>void):此;
on(事件:'error',侦听器:(err:error)=>void):此;
on(事件:字符串|符号,侦听器:(…args:any[])=>void):此;
一次(事件:“关闭”,侦听器:()=>void):此;
一次(事件:'data',侦听器:(chunk:T)=>void):这个;
一次(事件:'end',侦听器:()=>void):这个;
一次(事件:'readable',侦听器:()=>void):此;
一次(事件:'error',侦听器:(err:error)=>void):此;
一次(事件:字符串|符号,侦听器:(…args:any[])=>void):此;
prependListener(事件:'close',侦听器:()=>void):这个;
prependListener(事件:“数据”,侦听器:(chunk:T)=>void):这个;
prependListener(事件:'end',侦听器:()=>void):这个;
prependListener(事件:'readable',侦听器:()=>void):这个;
prependListener(事件:'error',监听器:(err:error)=>void):这个;
prependListener(事件:字符串|符号,侦听器:(…args:any[])=>void):这个;
PrependenceListener(事件:'close',监听器:()=>void):这个;
prependenceListener(事件:'data',侦听器:(chunk:T)=>void):这个;
PrependenceListener(事件:'end',侦听器:()=>void):这个;
PrependenceListener(事件:“可读”,侦听器:()=>void):此;
PrependenceListener(事件:'error',listener:(err:error)=>void):这个;
PrependenceListener(事件:字符串|符号,侦听器:(…args:any[])=>void):这个;
RemovelListener(事件:'close',侦听器:()=>void):这个;
RemovelListener(事件:“数据”,侦听器:(chunk:T)=>void):这个;
RemovelListener(事件:'end',侦听器:()=>void):这个;
RemovelListener(事件:'readable',侦听器:()=>void):这个;
RemovelListener(事件:'error',侦听器:(err:error)=>void):这个;
RemovelListener(事件:字符串|符号,侦听器:(…args:any[])=>void):这个;
[Symbol.asyncIterator]():AsyncIterableIterator;
}
导出接口可读选项{
高水印?:数字;
编码?:字符串;
objectMode?:布尔型;
读?(这个:这个,大小:数字):无效;
毁灭(
这个,这个,,
错误:错误| null,
回拨:BasicCallback,
):无效;
}

通过扩展原始类别(可读、可写和转换),我以一种不同的方式面对这种情况,如:

从“Stream”导入{Stream};
导出类GenericTransform扩展了Stream.Transform{
private-processChunk:(chunk:K,enc:string)=>Promise;
构造函数(processChunk:(chunk:K,enc:string)=>Promise){
超级({objectMode:true});
this.processChunk=processChunk;
}
//eslint禁用下一行无下划线悬挂
公共异步转换(chunk:K,enc:string,cb:(error?:error | null)=>void):承诺{
试一试{
this.push(等待this.processChunk(chunk,enc));
cb();
}捕捉(错误){
cb(err);
}
}
}
export const createTransform=(transform:(chunk:K,enc:string)=>Promise:genericttransform=>new-genericttransform(transform);
使用方法如下:

  inputStream.pipe<GenericTransform<InputType, OutputType>>(
    createTransform<InputType, OutputType>(
      async (chunks: InputType): Promise<OutputType> => {
        await doWhatEver(chunks);
        return chunks;
      }
    )
  ).outputStream
inputStream.pipe(
createTransform(
异步(块:InputType):Promise=>{
等待doWhatEver(块);
返回块;
}
)
).输出流
同样,可以使用类似的泛型类创建输入流和输出流,以向它们添加类型

// Readable.d.ts
import { BasicCallback } from './core';

export interface Readable<T> extends ReadStream<T> {}
export class Readable<T> {
  constructor(opts?: ReadableOptions<Readable<T>>);

  _read?(size: number): void;
  _destroy?(error: Error | null, callback: BasicCallback): void;
}

export interface ReadStream<T> {
  readable: boolean;
  readonly readableHighWaterMark: number;
  readonly readableLength: number;
  read(size?: number): T;
  setEncoding(encoding: string): this;
  pause(): this;
  resume(): this;
  isPaused(): boolean;
  unpipe<T extends NodeJS.WritableStream>(destination?: T): this;
  unshift(chunk: T): void;
  wrap(oldStream: NodeJS.ReadableStream): this;
  push(chunk: T | null, encoding?: string): boolean;
  destroy(error?: Error): void;

  /**
   * Event emitter
   * The defined events on documents including:
   * 1. close
   * 2. data
   * 3. end
   * 4. readable
   * 5. error
   */
  addListener(event: 'close', listener: () => void): this;
  addListener(event: 'data', listener: (chunk: T) => void): this;
  addListener(event: 'end', listener: () => void): this;
  addListener(event: 'readable', listener: () => void): this;
  addListener(event: 'error', listener: (err: Error) => void): this;
  addListener(event: string | symbol, listener: (...args: any[]) => void): this;

  emit(event: 'close'): boolean;
  emit(event: 'data', chunk: T): boolean;
  emit(event: 'end'): boolean;
  emit(event: 'readable'): boolean;
  emit(event: 'error', err: Error): boolean;
  emit(event: string | symbol, ...args: any[]): boolean;

  on(event: 'close', listener: () => void): this;
  on(event: 'data', listener: (chunk: T) => void): this;
  on(event: 'end', listener: () => void): this;
  on(event: 'readable', listener: () => void): this;
  on(event: 'error', listener: (err: Error) => void): this;
  on(event: string | symbol, listener: (...args: any[]) => void): this;

  once(event: 'close', listener: () => void): this;
  once(event: 'data', listener: (chunk: T) => void): this;
  once(event: 'end', listener: () => void): this;
  once(event: 'readable', listener: () => void): this;
  once(event: 'error', listener: (err: Error) => void): this;
  once(event: string | symbol, listener: (...args: any[]) => void): this;

  prependListener(event: 'close', listener: () => void): this;
  prependListener(event: 'data', listener: (chunk: T) => void): this;
  prependListener(event: 'end', listener: () => void): this;
  prependListener(event: 'readable', listener: () => void): this;
  prependListener(event: 'error', listener: (err: Error) => void): this;
  prependListener(event: string | symbol, listener: (...args: any[]) => void): this;

  prependOnceListener(event: 'close', listener: () => void): this;
  prependOnceListener(event: 'data', listener: (chunk: T) => void): this;
  prependOnceListener(event: 'end', listener: () => void): this;
  prependOnceListener(event: 'readable', listener: () => void): this;
  prependOnceListener(event: 'error', listener: (err: Error) => void): this;
  prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;

  removeListener(event: 'close', listener: () => void): this;
  removeListener(event: 'data', listener: (chunk: T) => void): this;
  removeListener(event: 'end', listener: () => void): this;
  removeListener(event: 'readable', listener: () => void): this;
  removeListener(event: 'error', listener: (err: Error) => void): this;
  removeListener(event: string | symbol, listener: (...args: any[]) => void): this;

  [Symbol.asyncIterator](): AsyncIterableIterator<T>;
}

export interface ReadableOptions<This> {
  highWaterMark?: number;
  encoding?: string;
  objectMode?: boolean;
  read?(this: This, size: number): void;
  destroy?(
      this: This,
      error: Error | null,
      callback: BasicCallback,
      ): void;
}
import { Stream } from "stream";

export class GenericTransform<K, T> extends Stream.Transform {
  private processChunk: (chunk: K, enc: string) => Promise<T>;

  constructor(processChunk: (chunk: K, enc: string) => Promise<T>) {
    super({ objectMode: true });
    this.processChunk = processChunk;
  }

  // eslint-disable-next-line no-underscore-dangle
  public async _transform(chunk: K, enc: string, cb: (error?: Error | null) => void): Promise<void> {
    try {
      this.push(await this.processChunk(chunk, enc));
      cb();
    } catch (err) {
      cb(err);
    }
  }
}

export const createTransform = <K, T>(transform: (chunk: K, enc: string) => Promise<T>): GenericTransform<K, T> => new GenericTransform(transform);
  inputStream.pipe<GenericTransform<InputType, OutputType>>(
    createTransform<InputType, OutputType>(
      async (chunks: InputType): Promise<OutputType> => {
        await doWhatEver(chunks);
        return chunks;
      }
    )
  ).outputStream