logo hsb.horse
← Zur Blog-Übersicht

Blog

Eine TypeScript-Utility-Funktion zum Konvertieren von Werten in ReadableStream

Eine Utility-Funktion, die Strings, Objekte und andere Werte in ReadableStream umwandelt. Streams mit beliebigen Typen, ohne erst über Blob zu gehen.

Veröffentlicht:

Wenn man primitive Werte wie Strings oder auch Objekte in einen ReadableStream umwandeln will, ist ein häufiger Weg, sie zuerst in einen Blob zu konvertieren.

Das Problem dabei ist, dass ein über Blob erzeugter Stream zu Uint8Array wird. Das ist nicht unbedingt falsch, und für binäre Operationen ist es wahrscheinlich sogar der effizienteste Weg.

Trotzdem wollte ich eine kleine Utility-Funktion, die auch Strings und andere Werte direkt behandeln kann, also habe ich sie geschrieben.

Code

type StreamResource<T> = T extends Blob
? Uint8Array
: T extends Uint8Array | ArrayBuffer
? Uint8Array
: T extends undefined | null | symbol
? never
: T;
function toReadableStream<T>(value: T): ReadableStream<StreamResource<T>> {
if (value === undefined || value === null || typeof value === "symbol") {
throw new TypeError(
"Cannot convert undefined, null, or symbol to ReadableStream"
);
}
if (value instanceof Blob) {
return value.stream() as ReadableStream<StreamResource<T>>;
}
if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
const uint8Array = new Uint8Array(value);
return new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(uint8Array);
controller.close();
},
}) as ReadableStream<StreamResource<T>>;
}
return new ReadableStream<StreamResource<T>>({
start(controller) {
controller.enqueue(value as StreamResource<T>);
controller.close();
},
});
}

Anwendungsbeispiele

const blob = new Blob(['Hello, World!'], { type: 'text/plain' });
const blobStream = toReadableStream(blob);
// ^? ReadableStream<Uint8Array>
const buffer = new ArrayBuffer(8);
const bufferStream = toReadableStream(buffer);
// ^? ReadableStream<Uint8Array>
const uint8Array = new Uint8Array([1, 2, 3, 4]);
const uint8ArrayStream = toReadableStream(uint8Array);
// ^? ReadableStream<Uint8Array>
const str = 'Hello, TypeScript!';
const strStream = toReadableStream(str);
// ^? ReadableStream<string>
const num = 42;
const numStream = toReadableStream(num);
// ^? ReadableStream<number>
const undefStream = toReadableStream(undefined);
// ^? ReadableStream<never>

Wichtige Punkte

  • Typensichere Umwandlung mit Conditional Types
  • Blob und ArrayBuffer werden zu Uint8Array-Streams
  • string, number und ähnliche Werte bleiben in ihrem ursprünglichen Typ
  • undefined, null und symbol führen zu einem Typfehler

Zusammenfassung

Wenn Werte direkt in einen ReadableStream eingequeueed werden, lassen sich Streams flexibler erzeugen als über den Umweg Blob.

Da auch die Typinferenz gut funktioniert, ist das eine nützliche Utility-Funktion für TypeScript.