Readable.fromWeb(response.body)
类型报错?import * as class stream
stream from 'node:stream'
const const response: Response
response = await function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch('https://example.com')
if (const response: Response
response.Body.body: ReadableStream<Uint8Array<ArrayBuffer>> | null
body) {
class stream
stream.class Stream.Readable
Readable.Stream.Readable.fromWeb(readableStream: ReadableStream, options?: Pick<stream.ReadableOptions, "encoding" | "highWaterMark" | "objectMode" | "signal">): stream.Readable
fromWeb(response.Body.body: ReadableStream<Uint8Array<ArrayBuffer>>
body)}
观察 fetch
的类型,会发现他来自 lib.dom.d.ts,可是哪一行代码引入了 DOM 类型呢?
// tsconfig 里也没写 DOM ... 吗
{
"compilerOptions": {
"types": ["node"]
}
}
其实,不写 "lib"
等于引入了默认 lib,也就是 typescript/lib/lib.d.ts:
/// <reference lib="es5" />
/// <reference lib="dom" />
/// <reference lib="webworker.importscripts" />
/// <reference lib="scripthost" />
所以一个显而易见的修复方案是,手动指定一下 lib:
{
"compilerOptions": {
"lib": ["ES2024"], // <-- 没有 DOM
"types": ["node"]
}
}
但是这个办法只能在所有文件都是 Node.js 环境的才可以,实际项目可能组织成下面这样:
src/vs/base/common/disposable.ts
src/vs/base/node/fs.ts
src/vs/base/browser/dom.ts
src/tsconfig.json
(管所有文件)简单解释一下这个结构:
{源码文件夹}/{独立模块}/{运行环境}/{代码}.ts
独立模块们可能是由不同人开发的,但是相比 monorepo 里开一堆包,这个结构不需要额外写一大堆内容大部分重复的 package.json,也不需要在每个子包里精确管理依赖(只要最顶层这个包的依赖完整即可)。
根据运行环境分隔代码的好处是,开发者可以编写简单的 lint 插件 避免例如前端的代码引用了后端的问题。需要注意的是这种风格下最好避免使用 Barrel files (index.ts)。
这种情况下就不能避免 DOM 类型被引入了,解法是我们强行让 DOM 里的 Response 兼容 Node.js 里的:
import * as class stream
stream from 'node:stream'
// 注意到 DOM 里的 Response 是全局的, 可以通过 declare global 来修改他
import * as module "stream/web"
streamWeb from 'stream/web'
declare global {
interface Response {
Response.body: streamWeb.ReadableStream<Uint8Array<ArrayBufferLike>> | null
body: module "stream/web"
streamWeb.interface ReadableStream<R = any>
ReadableStream<interface Uint8Array<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike>
Uint8Array> | null
}
}
const const response: Response
response = await function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch('https://example.com')
if (const response: Response
response.Response.body: streamWeb.ReadableStream<Uint8Array<ArrayBufferLike>> | null
body) {
class stream
stream.class Stream.Readable
Readable.Stream.Readable.fromWeb(readableStream: streamWeb.ReadableStream, options?: Pick<stream.ReadableOptions, "encoding" | "highWaterMark" | "objectMode" | "signal">): stream.Readable
fromWeb(const response: Response
response.Response.body: streamWeb.ReadableStream<Uint8Array<ArrayBufferLike>>
body)
}