Typescript:有没有更好的方法来获取类型化流?
对象流很好,但它们目前是非类型化的,这意味着您可以将无意义的流连接在一起。嘘 目标(ish)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
所以,这里有更好的方法 首先,定义(代码库中的某个地方)一个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