Support TypeScript 5.9 (#21539)

### What does this PR do?

Fixes #21535

### How did you verify your code works?
This commit is contained in:
Alistair Smith
2025-08-01 16:09:44 -07:00
committed by GitHub
parent 0cf2b71ff1
commit d0edcc69ae
21 changed files with 507 additions and 207 deletions

View File

@@ -15,7 +15,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"source-map-js": "^1.2.0",
"typescript": "^5.7.2",
"typescript": "5.9.2",
},
},
"packages/@types/bun": {
@@ -32,7 +32,6 @@
},
"devDependencies": {
"@types/react": "^19",
"typescript": "^5.0.2",
},
"peerDependencies": {
"@types/react": "^19",
@@ -308,7 +307,7 @@
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
@@ -334,6 +333,8 @@
"@octokit/webhooks/@octokit/webhooks-methods": ["@octokit/webhooks-methods@4.1.0", "", {}, "sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ=="],
"bun-tracestrings/typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"camel-case/no-case": ["no-case@2.3.2", "", { "dependencies": { "lower-case": "^1.1.1" } }, "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ=="],
"change-case/camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="],

View File

@@ -208,8 +208,8 @@ export class ArrayBufferSink {
*
* This API might change later to separate Uint8ArraySink and ArrayBufferSink
*/
flush(): number | Uint8Array | ArrayBuffer;
end(): ArrayBuffer | Uint8Array;
flush(): number | Uint8Array<ArrayBuffer> | ArrayBuffer;
end(): ArrayBuffer | Uint8Array<ArrayBuffer>;
}
```

View File

@@ -14,7 +14,7 @@ if (typeof Bun !== "undefined") {
---
In TypeScript environments, the previous approach will result in a type error unless `bun-types` is globally installed. To avoid this, you can check `process.versions` instead.
In TypeScript environments, the previous approach will result in a type error unless `@types/bun` is installed. To avoid this, you can check `process.versions` instead.
```ts
if (process.versions.bun) {

View File

@@ -18,7 +18,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"source-map-js": "^1.2.0",
"typescript": "^5.7.2"
"typescript": "5.9.2"
},
"resolutions": {
"bun-types": "workspace:packages/bun-types",

View File

@@ -21,7 +21,7 @@ declare module "bun" {
| DataView<TArrayBuffer>;
type BufferSource = NodeJS.TypedArray | DataView | ArrayBufferLike;
type StringOrBuffer = string | NodeJS.TypedArray | ArrayBufferLike;
type XMLHttpRequestBodyInit = Blob | BufferSource | string | FormData | Iterable<Uint8Array>;
type XMLHttpRequestBodyInit = Blob | BufferSource | FormData | URLSearchParams | string;
type ReadableStreamController<T> = ReadableStreamDefaultController<T>;
type ReadableStreamDefaultReadResult<T> =
| ReadableStreamDefaultReadValueResult<T>
@@ -826,7 +826,7 @@ declare module "bun" {
buffers: Array<ArrayBufferView | ArrayBufferLike>,
maxLength: number,
asUint8Array: true,
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
@@ -843,35 +843,6 @@ declare module "bun" {
stream: ReadableStream<ArrayBufferView | ArrayBufferLike>,
): Promise<ArrayBuffer> | ArrayBuffer;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link ArrayBuffer}.
*
* Each chunk must be a TypedArray or an ArrayBuffer. If you need to support
* chunks of different types, consider {@link readableStreamToBlob}
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks or the concatenated chunks as a {@link Uint8Array}.
*
* @deprecated Use {@link ReadableStream.bytes}
*/
function readableStreamToBytes(
stream: ReadableStream<ArrayBufferView | ArrayBufferLike>,
): Promise<Uint8Array> | Uint8Array;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link Blob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link Blob}.
*
* @deprecated Use {@link ReadableStream.blob}
*/
function readableStreamToBlob(stream: ReadableStream): Promise<Blob>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
@@ -904,30 +875,6 @@ declare module "bun" {
multipartBoundaryExcludingDashes?: string | NodeJS.TypedArray | ArrayBufferView,
): Promise<FormData>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*
* @deprecated Use {@link ReadableStream.text}
*/
function readableStreamToText(stream: ReadableStream): Promise<string>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string and parse as JSON. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*
* @deprecated Use {@link ReadableStream.json}
*/
function readableStreamToJSON(stream: ReadableStream): Promise<any>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
@@ -1027,8 +974,8 @@ declare module "bun" {
*
* This API might change later to separate Uint8ArraySink and ArrayBufferSink
*/
flush(): number | Uint8Array | ArrayBuffer;
end(): ArrayBuffer | Uint8Array;
flush(): number | Uint8Array<ArrayBuffer> | ArrayBuffer;
end(): ArrayBuffer | Uint8Array<ArrayBuffer>;
}
/** DNS Related APIs */
@@ -1595,13 +1542,18 @@ declare module "bun" {
* Executes a SQL query using template literals
* @example
* ```ts
* const [user] = await sql`select * from users where id = ${1}`;
* const [user] = await sql<Users[]>`select * from users where id = ${1}`;
* ```
*/
<T = any>(strings: TemplateStringsArray, ...values: unknown[]): SQL.Query<T>;
/**
* Execute a SQL query using a string
*
* @example
* ```ts
* const users = await sql<User[]>`SELECT * FROM users WHERE id = ${1}`;
* ```
*/
<T = any>(string: string): SQL.Query<T>;
@@ -1620,6 +1572,23 @@ declare module "bun" {
* const result = await sql`insert into users ${sql(user)} returning *`;
* ```
*/
<T extends { [Key in PropertyKey]: unknown }>(obj: T | T[] | readonly T[]): SQL.Helper<T>;
/**
* Helper function for inserting an object into a query, supporting specific columns
*
* @example
* ```ts
* // Insert an object
* const result = await sql`insert into users ${sql(users)} returning *`;
*
* // Or pick specific columns
* const result = await sql`insert into users ${sql(users, "id", "name")} returning *`;
*
* // Or a single object
* const result = await sql`insert into users ${sql(user)} returning *`;
* ```
*/
<T extends { [Key in PropertyKey]: unknown }, Keys extends keyof T = keyof T>(
obj: T | T[] | readonly T[],
...columns: readonly Keys[]
@@ -3682,7 +3651,7 @@ declare module "bun" {
/**
* If set, the HTTP server will listen on a unix socket instead of a port.
* (Cannot be used with hostname+port)
* (Cannot use unix with port + hostname)
*/
unix?: never;
@@ -3705,9 +3674,21 @@ declare module "bun" {
interface UnixServeOptions extends GenericServeOptions {
/**
* If set, the HTTP server will listen on a unix socket instead of a port.
* (Cannot be used with hostname+port)
*/
unix: string;
/**
* If set, the HTTP server will listen on this port
* (Cannot use port with unix)
*/
port?: never;
/**
* If set, the HTTP server will listen on this hostname
* (Cannot use hostname with unix)
*/
hostname?: never;
/**
* Handle HTTP requests
*
@@ -4635,7 +4616,7 @@ declare module "bun" {
*
* @param path The path to the file as a byte buffer (the buffer is copied) if the path starts with `s3://` it will behave like {@link S3File}
*/
function file(path: ArrayBufferLike | Uint8Array, options?: BlobPropertyBag): BunFile;
function file(path: ArrayBufferLike | Uint8Array<ArrayBuffer>, options?: BlobPropertyBag): BunFile;
/**
* [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) powered by the fastest system calls available for operating on files.
@@ -4658,7 +4639,7 @@ declare module "bun" {
*
* This can be 3.5x faster than `new Uint8Array(size)`, but if you send uninitialized memory to your users (even unintentionally), it can potentially leak anything recently in memory.
*/
function allocUnsafe(size: number): Uint8Array;
function allocUnsafe(size: number): Uint8Array<ArrayBuffer>;
/**
* Options for `Bun.inspect`
@@ -4941,7 +4922,7 @@ declare module "bun" {
*
* To close the file, set the array to `null` and it will be garbage collected eventually.
*/
function mmap(path: PathLike, opts?: MMapOptions): Uint8Array;
function mmap(path: PathLike, opts?: MMapOptions): Uint8Array<ArrayBuffer>;
/**
* Write to stdout
@@ -4971,8 +4952,8 @@ declare module "bun" {
| { r: number; g: number; b: number; a?: number }
| [number, number, number]
| [number, number, number, number]
| Uint8Array
| Uint8ClampedArray
| Uint8Array<ArrayBuffer>
| Uint8ClampedArray<ArrayBuffer>
| Float32Array
| Float64Array
| string
@@ -5095,7 +5076,7 @@ declare module "bun" {
*
* **The input buffer must not be garbage collected**. That means you will need to hold on to it for the duration of the string's lifetime.
*/
function arrayBufferToString(buffer: Uint8Array | ArrayBufferLike): string;
function arrayBufferToString(buffer: Uint8Array<ArrayBuffer> | ArrayBufferLike): string;
/**
* Cast bytes to a `String` without copying. This is the fastest way to get a `String` from a `Uint16Array`
@@ -5644,9 +5625,9 @@ declare module "bun" {
* @returns The output buffer with the compressed data
*/
function deflateSync(
data: Uint8Array | string | ArrayBuffer,
data: Uint8Array<ArrayBuffer> | string | ArrayBuffer,
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Compresses a chunk of data with `zlib` GZIP algorithm.
* @param data The buffer of data to compress
@@ -5654,27 +5635,27 @@ declare module "bun" {
* @returns The output buffer with the compressed data
*/
function gzipSync(
data: Uint8Array | string | ArrayBuffer,
data: Uint8Array<ArrayBuffer> | string | ArrayBuffer,
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Decompresses a chunk of data with `zlib` INFLATE algorithm.
* @param data The buffer of data to decompress
* @returns The output buffer with the decompressed data
*/
function inflateSync(
data: Uint8Array | string | ArrayBuffer,
data: Uint8Array<ArrayBuffer> | string | ArrayBuffer,
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Decompresses a chunk of data with `zlib` GUNZIP algorithm.
* @param data The buffer of data to decompress
* @returns The output buffer with the decompressed data
*/
function gunzipSync(
data: Uint8Array | string | ArrayBuffer,
data: Uint8Array<ArrayBuffer> | string | ArrayBuffer,
options?: ZlibCompressionOptions | LibdeflateCompressionOptions,
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Compresses a chunk of data with the Zstandard (zstd) compression algorithm.
@@ -6651,7 +6632,7 @@ declare module "bun" {
interface BinaryTypeList {
arraybuffer: ArrayBuffer;
buffer: Buffer;
uint8array: Uint8Array;
uint8array: Uint8Array<ArrayBuffer>;
// TODO: DataView
// dataview: DataView;
}
@@ -6829,6 +6810,7 @@ declare module "bun" {
* The unix socket to listen on or connect to
*/
unix: string;
/**
* TLS Configuration with which to create the socket
*/
@@ -7223,7 +7205,7 @@ declare module "bun" {
}
type ReadableToIO<X extends Readable> = X extends "pipe" | undefined
? ReadableStream<Uint8Array>
? ReadableStream<Uint8Array<ArrayBuffer>>
: X extends BunFile | ArrayBufferView | number
? number
: undefined;

View File

@@ -1,4 +1,57 @@
declare module "bun" {
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link ArrayBuffer}.
*
* Each chunk must be a TypedArray or an ArrayBuffer. If you need to support
* chunks of different types, consider {@link readableStreamToBlob}
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks or the concatenated chunks as a {@link Uint8Array}.
*
* @deprecated Use {@link ReadableStream.bytes}
*/
function readableStreamToBytes(
stream: ReadableStream<ArrayBufferView | ArrayBufferLike>,
): Promise<Uint8Array<ArrayBuffer>> | Uint8Array<ArrayBuffer>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link Blob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link Blob}.
*
* @deprecated Use {@link ReadableStream.blob}
*/
function readableStreamToBlob(stream: ReadableStream): Promise<Blob>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*
* @deprecated Use {@link ReadableStream.text}
*/
function readableStreamToText(stream: ReadableStream): Promise<string>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string and parse as JSON. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*
* @deprecated Use {@link ReadableStream.json}
*/
function readableStreamToJSON(stream: ReadableStream): Promise<any>;
interface BunMessageEvent<T> {
/**
* @deprecated
@@ -31,6 +84,9 @@ declare module "bun" {
*/
type Errorlike = ErrorLike;
/** @deprecated This is unused in Bun's types and may be removed in the future */
type ShellFunction = (input: Uint8Array<ArrayBuffer>) => Uint8Array<ArrayBuffer>;
interface TLSOptions {
/**
* File path to a TLS key
@@ -59,7 +115,7 @@ declare module "bun" {
}
/** @deprecated This type is unused in Bun's declarations and may be removed in the future */
type ReadableIO = ReadableStream<Uint8Array> | number | undefined;
type ReadableIO = ReadableStream<Uint8Array<ArrayBuffer>> | number | undefined;
}
declare namespace NodeJS {

View File

@@ -1,19 +1,21 @@
/*
This file does not declare any global types.
That should only happen in [./globals.d.ts](./globals.d.ts)
so that our documentation generator can pick it up, as it
expects all globals to be declared in one file.
* This file does not declare any global types.
*
* That should only happen in [./globals.d.ts](./globals.d.ts)
* so that our documentation generator can pick it up, as it
* expects all globals to be declared in one file.
*
* This may change in the future, which would be
* a nice thing as it would allow us to split up
* relevant types into their own files.
*/
declare module "bun" {
type HeadersInit = string[][] | Record<string, string | ReadonlyArray<string>> | Headers;
type BodyInit =
| ReadableStream
| Bun.XMLHttpRequestBodyInit
| URLSearchParams
// Extras that Bun supports:
| AsyncIterable<string | ArrayBuffer | ArrayBufferView>
| AsyncGenerator<string | ArrayBuffer | ArrayBufferView>
| (() => AsyncGenerator<string | ArrayBuffer | ArrayBufferView>);
@@ -26,7 +28,7 @@ declare module "bun" {
? {}
: Omit<import("undici-types").RequestInit, "body" | "headers"> & {
body?: Bun.BodyInit | null | undefined;
headers?: Bun.HeadersInit;
headers?: Bun.HeadersInit | undefined;
};
interface BunHeadersOverride extends LibOrFallbackHeaders {

View File

@@ -999,6 +999,7 @@ interface ArrayBuffer {
* Read-only. The length of the ArrayBuffer (in bytes).
*/
readonly byteLength: number;
/**
* Resize an ArrayBuffer in-place.
*/
@@ -1008,7 +1009,6 @@ interface ArrayBuffer {
* Returns a section of an ArrayBuffer.
*/
slice(begin: number, end?: number): ArrayBuffer;
readonly [Symbol.toStringTag]: string;
}
interface SharedArrayBuffer {
@@ -1426,12 +1426,12 @@ interface Blob {
/**
* Returns a promise that resolves to the contents of the blob as a Uint8Array (array of bytes) its the same as `new Uint8Array(await blob.arrayBuffer())`
*/
bytes(): Promise<Uint8Array>;
bytes(): Promise<Uint8Array<ArrayBuffer>>;
/**
* Returns a readable stream of the blob's contents
*/
stream(): ReadableStream<Uint8Array>;
stream(): ReadableStream<Uint8Array<ArrayBuffer>>;
}
declare var Blob: Bun.__internal.UseLibDomIfAvailable<
@@ -1506,14 +1506,14 @@ interface Uint8ArrayConstructor {
alphabet?: "base64" | "base64url";
lastChunkHandling?: "loose" | "strict" | "stop-before-partial";
},
): Uint8Array;
): Uint8Array<ArrayBuffer>;
/**
* Create a new Uint8Array from a hex encoded string
* @param hex The hex encoded string to convert to a Uint8Array
* @returns A new Uint8Array containing the decoded data
*/
fromHex(hex: string): Uint8Array;
fromHex(hex: string): Uint8Array<ArrayBuffer>;
}
interface BroadcastChannel extends Bun.__internal.LibEmptyOrBroadcastChannel {}

View File

@@ -6,14 +6,17 @@ declare module "stream/web" {
* Consume a ReadableStream as text
*/
text(): Promise<string>;
/**
* Consume a ReadableStream as a Uint8Array
*/
bytes(): Promise<Uint8Array>;
bytes(): Promise<Uint8Array<ArrayBuffer>>;
/**
* Consume a ReadableStream as JSON
*/
json(): Promise<any>;
/**
* Consume a ReadableStream as a Blob
*/

View File

@@ -10,11 +10,11 @@
},
"files": [
"./*.d.ts",
"vendor/**/*.d.ts",
"docs/**/*.md",
"docs/*.md",
"CLAUDE.md",
"README.md"
"./vendor/**/*.d.ts",
"./docs/**/*.md",
"./docs/*.md",
"./CLAUDE.md",
"./README.md"
],
"homepage": "https://bun.com",
"dependencies": {
@@ -24,8 +24,7 @@
"@types/react": "^19"
},
"devDependencies": {
"@types/react": "^19",
"typescript": "^5.0.2"
"@types/react": "^19"
},
"scripts": {
"prebuild": "echo $(pwd)",

View File

@@ -487,8 +487,8 @@ declare module "bun" {
* // Process text chunk by chunk
* }
*/
readonly readable: ReadableStream;
stream(): ReadableStream;
readonly readable: ReadableStream<Uint8Array<ArrayBuffer>>;
stream(): ReadableStream<Uint8Array<ArrayBuffer>>;
/**
* The name or path of the file in the bucket.

View File

@@ -1,6 +1,4 @@
declare module "bun" {
type ShellFunction = (input: Uint8Array) => Uint8Array;
type ShellExpression =
| { toString(): string }
| Array<ShellExpression>
@@ -294,7 +292,7 @@ declare module "bun" {
* console.log(output.bytes()); // Uint8Array { byteLength: 6 }
* ```
*/
bytes(): Uint8Array;
bytes(): Uint8Array<ArrayBuffer>;
}
interface ShellOutput {
@@ -361,7 +359,7 @@ declare module "bun" {
* console.log(output.bytes()); // Uint8Array { byteLength: 6 }
* ```
*/
bytes(): Uint8Array;
bytes(): Uint8Array<ArrayBuffer>;
/**
* Read from stdout as a Blob

View File

@@ -91,7 +91,7 @@
"tsyringe": "4.8.0",
"type-graphql": "2.0.0-rc.2",
"typeorm": "0.3.20",
"typescript": "5.8.3",
"typescript": "5.9.2",
"undici": "5.20.0",
"unzipper": "0.12.3",
"uuid": "11.1.0",
@@ -2502,7 +2502,7 @@
"typeorm": ["typeorm@0.3.20", "", { "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", "dayjs": "^1.11.9", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^10.3.10", "mkdirp": "^2.1.3", "reflect-metadata": "^0.2.1", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", "yargs": "^17.6.2" }, "peerDependencies": { "@google-cloud/spanner": "^5.18.0", "@sap/hana-client": "^2.12.25", "better-sqlite3": "^7.1.2 || ^8.0.0 || ^9.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", "mongodb": "^5.8.0", "mssql": "^9.1.1 || ^10.0.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^6.3.0", "pg": "^8.5.1", "pg-native": "^3.0.0", "pg-query-stream": "^4.0.0", "redis": "^3.1.1 || ^4.0.0", "sql.js": "^1.4.0", "sqlite3": "^5.0.3", "ts-node": "^10.7.0", "typeorm-aurora-data-api-driver": "^2.0.0" }, "optionalPeers": ["@google-cloud/spanner", "@sap/hana-client", "better-sqlite3", "hdb-pool", "ioredis", "mongodb", "mssql", "mysql2", "oracledb", "pg", "pg-native", "pg-query-stream", "redis", "sql.js", "sqlite3", "ts-node", "typeorm-aurora-data-api-driver"], "bin": { "typeorm": "cli.js", "typeorm-ts-node-esm": "cli-ts-node-esm.js", "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js" } }, "sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="],

View File

@@ -56,7 +56,7 @@ beforeAll(async () => {
cd ${BUN_TYPES_PACKAGE_ROOT}
bun run build
bun pm pack --destination ${FIXTURE_DIR}
exit 0
rm CLAUDE.md
mv package.json.backup package.json
cd ${FIXTURE_DIR}
@@ -140,6 +140,14 @@ async function diagnose(
const program = service.getProgram();
if (!program) throw new Error("Failed to create program");
function getLine(diagnostic: ts.Diagnostic) {
if (!diagnostic.file) return null;
if (diagnostic.start === undefined) return null;
const lineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
return `${relative(fixtureDir, diagnostic.file.fileName)}:${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`;
}
const diagnostics = ts
.getPreEmitDiagnostics(program)
.concat(program.getOptionsDiagnostics())
@@ -148,19 +156,18 @@ async function diagnose(
.concat(program.getDeclarationDiagnostics())
.concat(program.emit().diagnostics)
.map(diagnostic => ({
category: ts.DiagnosticCategory[diagnostic.category],
file: diagnostic.file?.fileName ? relative(fixtureDir, diagnostic.file?.fileName) : null,
line: getLine(diagnostic),
message: typeof diagnostic.messageText === "string" ? diagnostic.messageText : diagnostic.messageText.messageText,
code: diagnostic.code,
}));
return {
diagnostics,
emptyInterfaces: checkForEmptyInterfaces(program, fixtureDir),
emptyInterfaces: checkForEmptyInterfaces(program),
};
}
function checkForEmptyInterfaces(program: ts.Program, fixtureDir: string) {
function checkForEmptyInterfaces(program: ts.Program) {
const empties = new Set<string>();
const checker = program.getTypeChecker();
@@ -179,7 +186,6 @@ function checkForEmptyInterfaces(program: ts.Program, fixtureDir: string) {
const concernsBun = declarations.some(decl => decl.getSourceFile().fileName.includes("node_modules/@types/bun"));
if (!concernsBun) {
// the lion is not concerned by symbols outside of bun
continue;
}
@@ -225,7 +231,8 @@ afterAll(async () => {
console.log(TEMP_DIR);
if (Bun.env.TYPES_INTEGRATION_TEST_KEEP_TEMP_DIR === "true") {
console.log(`Keeping temp dir ${TEMP_DIR} for debugging`);
console.log(`Keeping temp dir ${TEMP_DIR}/fixture for debugging`);
await cp(TSCONFIG_SOURCE_PATH, join(TEMP_DIR, "fixture", "tsconfig.json"));
} else {
await rm(TEMP_DIR, { recursive: true, force: true });
}
@@ -278,6 +285,17 @@ describe("@types/bun integration test", () => {
});
});
test("checks with no lib at all", async () => {
const { diagnostics, emptyInterfaces } = await diagnose(FIXTURE_DIR, {
options: {
lib: [],
},
});
expect(emptyInterfaces).toEqual(new Set());
expect(diagnostics).toEqual([]);
});
test("checks with lib.dom.d.ts", async () => {
const { diagnostics, emptyInterfaces } = await diagnose(FIXTURE_DIR, {
options: {
@@ -288,204 +306,186 @@ describe("@types/bun integration test", () => {
expect(emptyInterfaces).toEqual(new Set());
expect(diagnostics).toEqual([
{
category: "Error",
file: "globals.ts",
code: 2769,
line: "fetch.ts:25:32",
message: "No overload matches this call.",
},
{
code: 2769,
line: "fetch.ts:33:32",
message: "No overload matches this call.",
},
{
code: 2769,
line: "fetch.ts:169:36",
message: "No overload matches this call.",
},
{
line: "globals.ts:307:5",
message: "Object literal may only specify known properties, and 'headers' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "http.ts",
line: "http.ts:43:24",
message:
"Argument of type '() => AsyncGenerator<Uint8Array<ArrayBuffer> | \"hey\", void, unknown>' is not assignable to parameter of type 'BodyInit | null | undefined'.",
code: 2345,
},
{
category: "Error",
file: "http.ts",
line: "http.ts:55:24",
message:
"Argument of type 'AsyncGenerator<Uint8Array<ArrayBuffer> | \"it works!\", void, unknown>' is not assignable to parameter of type 'BodyInit | null | undefined'.",
code: 2345,
},
{
category: "Error",
file: "index.ts",
line: "index.ts:193:14",
message:
"Argument of type 'AsyncGenerator<Uint8Array<ArrayBuffer>, void, unknown>' is not assignable to parameter of type 'BodyInit | null | undefined'.",
code: 2345,
},
{
category: "Error",
file: "index.ts",
line: "index.ts:323:29",
message:
"Argument of type '{ headers: { \"x-bun\": string; }; }' is not assignable to parameter of type 'number'.",
code: 2345,
},
{
category: "Error",
file: "spawn.ts",
message: "Property 'text' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
line: "spawn.ts:62:38",
message: "Property 'text' does not exist on type 'ReadableStream<Uint8Array<ArrayBuffer>>'.",
code: 2339,
},
{
category: "Error",
file: "spawn.ts",
message: "Property 'text' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
line: "spawn.ts:107:38",
message: "Property 'text' does not exist on type 'ReadableStream<Uint8Array<ArrayBuffer>>'.",
code: 2339,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:16:3",
message: "No overload matches this call.",
code: 2769,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:18:16",
message: "Property 'write' does not exist on type 'ReadableByteStreamController'.",
code: 2339,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:44:19",
message: "Property 'json' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
code: 2339,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:45:19",
message: "Property 'bytes' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
code: 2339,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:46:19",
message: "Property 'text' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
code: 2339,
},
{
category: "Error",
file: "streams.ts",
line: "streams.ts:47:19",
message: "Property 'blob' does not exist on type 'ReadableStream<Uint8Array<ArrayBufferLike>>'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:25:5",
message: "Object literal may only specify known properties, and 'protocols' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:30:5",
message: "Object literal may only specify known properties, and 'protocol' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:35:5",
message: "Object literal may only specify known properties, and 'protocol' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:43:5",
message: "Object literal may only specify known properties, and 'headers' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:51:5",
message: "Object literal may only specify known properties, and 'protocols' does not exist in type 'string[]'.",
code: 2353,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:185:29",
message: "Expected 2 arguments, but got 0.",
code: 2554,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:192:17",
message: "Property 'URL' does not exist on type 'WebSocket'. Did you mean 'url'?",
code: 2551,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:196:3",
message: "Type '\"nodebuffer\"' is not assignable to type 'BinaryType'.",
code: 2322,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:242:6",
message: "Property 'ping' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:245:6",
message: "Property 'ping' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:249:6",
message: "Property 'ping' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:253:6",
message: "Property 'ping' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:256:6",
message: "Property 'pong' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:259:6",
message: "Property 'pong' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:263:6",
message: "Property 'pong' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:267:6",
message: "Property 'pong' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "websocket.ts",
line: "websocket.ts:270:6",
message: "Property 'terminate' does not exist on type 'WebSocket'.",
code: 2339,
},
{
category: "Error",
file: "worker.ts",
line: "worker.ts:23:11",
message: "Property 'ref' does not exist on type 'Worker'.",
code: 2339,
},
{
category: "Error",
file: "worker.ts",
line: "worker.ts:24:11",
message: "Property 'unref' does not exist on type 'Worker'.",
code: 2339,
},
{
category: "Error",
file: "worker.ts",
line: "worker.ts:25:11",
message: "Property 'threadId' does not exist on type 'Worker'.",
code: 2339,
},

View File

@@ -1,3 +1,5 @@
import { expectType } from "./utilities";
const buffer = new ArrayBuffer(1024, {
maxByteLength: 2048,
});
@@ -9,3 +11,5 @@ TextDecoder;
const buf = new SharedArrayBuffer(1024);
buf.grow(2048);
expectType(buffer[Symbol.toStringTag]).extends<string>();

View File

@@ -0,0 +1,248 @@
// Valid body types
fetch("https://example.com", { body: "string body" });
fetch("https://example.com", { body: JSON.stringify({ key: "value" }) });
fetch("https://example.com", { body: new Blob(["blob content"]) });
fetch("https://example.com", { body: new File(["file content"], "file.txt") });
fetch("https://example.com", { body: new ArrayBuffer(8) });
fetch("https://example.com", { body: new Uint8Array([1, 2, 3, 4]) });
fetch("https://example.com", { body: new Int32Array([1, 2, 3, 4]) });
fetch("https://example.com", { body: new DataView(new ArrayBuffer(8)) });
fetch("https://example.com", { body: new URLSearchParams({ key: "value" }) });
fetch("https://example.com", { body: new FormData() });
fetch("https://example.com", { body: new ReadableStream() });
fetch("https://example.com", { body: Buffer.from("buffer content") });
fetch("https://example.com", { body: Bun.file("path") });
fetch("https://example.com", { body: Bun.file("hey").stream() });
fetch("https://example.com", { body: new Response("bun").body });
fetch("https://example.com", { body: Bun.s3.file("hey") });
fetch("https://example.com", { body: Bun.s3.file("hey").stream() });
fetch("https://example.com", { body: Bun.s3.file("hey").readable });
async function* asyncGenerator() {
yield "chunk1";
yield "chunk2";
}
fetch("https://example.com", { body: asyncGenerator() });
const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield "data1";
yield "data2";
},
};
fetch("https://example.com", { body: asyncIterable });
fetch("https://example.com").then(res => {
fetch("https://example.com", { body: res.body });
});
const req = new Request("https://example.com", { body: "request body" });
fetch("https://example.com", { body: req.body });
fetch("https://example.com", { body: null });
fetch("https://example.com", { body: undefined });
fetch("https://example.com", {}); // No body
{
function* syncGenerator() {
yield new Uint8Array([1, 2, 3]);
yield new Uint8Array([4, 5, 6]);
}
// @ts-expect-error Unsupported
fetch("https://example.com", { body: syncGenerator() });
}
{
const iterable = {
*[Symbol.iterator]() {
yield new Uint8Array([7, 8, 9]);
},
};
// @ts-expect-error normal iterators are not supported
fetch("https://example.com", { body: iterable });
}
{
// @ts-expect-error
fetch("https://example.com", { body: 123 });
}
{
// @ts-expect-error
fetch("https://example.com", { body: true });
}
{
// @ts-expect-error
fetch("https://example.com", { body: false });
}
{
// @ts-expect-error
fetch("https://example.com", { body: { plain: "object" } });
}
{
// @ts-expect-error
fetch("https://example.com", { body: ["array", "of", "strings"] });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new Date() });
}
{
// @ts-expect-error
fetch("https://example.com", { body: /regex/ });
}
{
// @ts-expect-error
fetch("https://example.com", { body: Symbol("symbol") });
}
{
// @ts-expect-error
fetch("https://example.com", { body: BigInt(123) });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new Map() });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new Set() });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new WeakMap() });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new WeakSet() });
}
{
// @ts-expect-error
fetch("https://example.com", { body: Promise.resolve("promise") });
}
{
// @ts-expect-error
fetch("https://example.com", { body: () => "function" });
}
{
// @ts-expect-error
fetch("https://example.com", { body: class MyClass {} });
}
{
// @ts-expect-error
fetch("https://example.com", { body: new Error("error") });
}
{
fetch("https://example.com", { method: "GET", body: "should not have body but types should still allow it" });
fetch("https://example.com", { method: "HEAD", body: "should not have body but types should still allow it" });
}
{
const multipartForm = new FormData();
multipartForm.append("field1", "value1");
multipartForm.append("file", new File(["content"], "test.txt"));
fetch("https://example.com", { body: multipartForm });
}
{
const searchParams = new URLSearchParams();
searchParams.append("key1", "value1");
searchParams.append("key2", "value2");
fetch("https://example.com", { body: searchParams });
}
{
fetch("https://example.com", { body: new SharedArrayBuffer(16) });
}
{
fetch("https://example.com", { body: new Float32Array([1.1, 2.2, 3.3]) });
fetch("https://example.com", { body: new Float64Array([1.1, 2.2, 3.3]) });
fetch("https://example.com", { body: new Int8Array([-128, 0, 127]) });
fetch("https://example.com", { body: new Uint16Array([0, 32768, 65535]) });
fetch("https://example.com", { body: new BigInt64Array([BigInt(1), BigInt(2)]) });
fetch("https://example.com", { body: new BigUint64Array([BigInt(1), BigInt(2)]) });
}
{
const textStream = new ReadableStream<string>({
start(controller) {
controller.enqueue("chunk1");
controller.enqueue("chunk2");
controller.close();
},
});
fetch("https://example.com", { body: textStream });
}
{
const byteStream = new ReadableStream<Uint8Array<ArrayBuffer>>({
start(controller) {
controller.enqueue(new Uint8Array([1, 2, 3]));
controller.enqueue(new Uint8Array([4, 5, 6]));
controller.close();
},
});
fetch("https://example.com", { body: byteStream });
}
{
async function notGenerator() {
return "not a generator";
}
// @ts-expect-error - Invalid async without generator
fetch("https://example.com", { body: notGenerator() });
}
{
const invalidIterable = {
notAnIterator() {
return "invalid";
},
};
// @ts-expect-error - Invalid object without proper iterator
fetch("https://example.com", { body: invalidIterable });
}
if (typeof process !== "undefined") {
// @ts-expect-error - Node.js specific invalid types
fetch("https://example.com", { body: process });
}
{
// @ts-expect-error - Invalid number array (not typed)
fetch("https://example.com", { body: [1, 2, 3, 4] });
}
{
// @ts-expect-error - Invalid nested structure
fetch("https://example.com", { body: { nested: { object: { structure: "invalid" } } } });
}
{
// @ts-expect-error - NaN
fetch("https://example.com", { body: NaN });
}
{
// @ts-expect-error - Infinity
fetch("https://example.com", { body: Infinity });
}
{
// @ts-expect-error - -Infinity
fetch("https://example.com", { body: -Infinity });
}

View File

@@ -181,7 +181,7 @@ for await (const chunk of Bun.stdin.stream()) {
// this converts it to text (assumes ASCII encoding)
const chunkText = Buffer.from(chunk).toString();
console.log(`Chunk: ${chunkText}`);
expectType(chunk).is<Uint8Array>();
expectType(chunk).is<Uint8Array<ArrayBuffer>>();
expectType(chunkText).is<string>();
}

View File

@@ -225,7 +225,6 @@ test(
test(
"basic unix socket + websocket + upgrade",
// @ts-expect-error - TODO Fix this
{
unix: `${tmpdirSync()}/bun.sock`,
fetch(req, server) {
@@ -246,7 +245,6 @@ test(
test(
"basic unix socket + websocket + upgrade + tls",
// @ts-expect-error - TODO Fix this
{
unix: `${tmpdirSync()}/bun.sock`,
fetch(req, server) {
@@ -286,7 +284,6 @@ test(
test(
"basic unix socket + upgrade + cheap request to check upgrade",
// @ts-expect-error - TODO Fix this
{
unix: `${tmpdirSync()}/bun.sock`,
fetch(req, server) {
@@ -507,10 +504,11 @@ test("basic websocket upgrade and ws publish/subscribe to topics", {
test(
"port with unix socket (is a type error)",
{
unix: `${tmpdirSync()}/bun.sock`,
// @ts-expect-error
port: 0,
// This prettier-ignore exists because between TypeScript 5.8 and 5.9, the location of the error message changed, so
// to satisfy both we can just keep what would have been the two erroring lines on the same line
// prettier-ignore
// @ts-expect-error
{ unix: `${tmpdirSync()}/bun.sock`, port: 0,
fetch() {
return new Response();
},
@@ -526,10 +524,10 @@ test(
test(
"port with unix socket with websocket + upgrade (is a type error)",
{
unix: `${tmpdirSync()}/bun.sock`,
// @ts-expect-error
port: 0,
// Prettier ignore exists for same reason as above
// prettier-ignore
// @ts-expect-error
{ unix: `${tmpdirSync()}/bun.sock`, port: 0,
fetch(req, server) {
server.upgrade(req);
if (Math.random() > 0.5) return undefined;

View File

@@ -49,7 +49,7 @@ function depromise<T>(_promise: Promise<T>): T {
tsd.expectType(proc.pid).is<number>();
tsd.expectType(proc.stdout).is<ReadableStream<Uint8Array>>();
tsd.expectType(proc.stdout).is<ReadableStream<Uint8Array<ArrayBuffer>>>();
tsd.expectType(proc.stderr).is<undefined>();
tsd.expectType(proc.stdin).is<undefined>();
}
@@ -74,8 +74,8 @@ function depromise<T>(_promise: Promise<T>): T {
tsd.expectType(proc.stdio[3]).is<number | undefined>();
tsd.expectType(proc.stdin).is<FileSink>();
tsd.expectType(proc.stdout).is<ReadableStream<Uint8Array>>();
tsd.expectType(proc.stderr).is<ReadableStream<Uint8Array>>();
tsd.expectType(proc.stdout).is<ReadableStream<Uint8Array<ArrayBuffer>>>();
tsd.expectType(proc.stderr).is<ReadableStream<Uint8Array<ArrayBuffer>>>();
}
{

View File

@@ -42,10 +42,19 @@ for await (const chunk of uint8Transform.readable) {
declare const stream: ReadableStream<Uint8Array>;
expectType(stream.json()).is<Promise<any>>();
expectType(stream.bytes()).is<Promise<Uint8Array>>();
expectType(stream.bytes()).is<Promise<Uint8Array<ArrayBuffer>>>();
expectType(stream.text()).is<Promise<string>>();
expectType(stream.blob()).is<Promise<Blob>>();
import { ReadableStream as NodeStreamReadableStream } from "node:stream/web";
declare const node_stream: NodeStreamReadableStream<Uint8Array>;
expectType(node_stream.json()).is<Promise<any>>();
expectType(node_stream.bytes()).is<Promise<Uint8Array<ArrayBuffer>>>();
expectType(node_stream.text()).is<Promise<string>>();
expectType(node_stream.blob()).is<Promise<Blob>>();
Bun.file("./foo.csv").stream().pipeThrough(new TextDecoderStream()).pipeThrough(new TextEncoderStream());
Bun.file("./foo.csv")

View File

@@ -96,7 +96,7 @@
"tsyringe": "4.8.0",
"type-graphql": "2.0.0-rc.2",
"typeorm": "0.3.20",
"typescript": "5.8.3",
"typescript": "5.9.2",
"undici": "5.20.0",
"unzipper": "0.12.3",
"uuid": "11.1.0",