Remove dependency on React's types in @types/bun

This commit is contained in:
Alistair Smith
2025-11-10 15:50:45 -08:00
committed by GitHub
parent 05d0475c6c
commit d87a928b94
6 changed files with 42 additions and 470 deletions

View File

@@ -31,12 +31,6 @@
"dependencies": { "dependencies": {
"@types/node": "*", "@types/node": "*",
}, },
"devDependencies": {
"@types/react": "^19",
},
"peerDependencies": {
"@types/react": "^19",
},
}, },
}, },
"overrides": { "overrides": {
@@ -162,8 +156,6 @@
"@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], "@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
"@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],
@@ -192,8 +184,6 @@
"constant-case": ["constant-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case": "^2.0.2" } }, "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ=="], "constant-case": ["constant-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case": "^2.0.2" } }, "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="],
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],

View File

@@ -1,278 +0,0 @@
declare module "bun" {
export namespace __experimental {
/**
* Base interface for static site generation route parameters.
*
* Supports both single string values and arrays of strings for dynamic route segments.
* This is typically used for route parameters like `[slug]`, `[...rest]`, or `[id]`.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @example
* ```tsx
* // Simple slug parameter
* type BlogParams = { slug: string };
*
* // Multiple parameters
* type ProductParams = {
* category: string;
* id: string;
* };
*
* // Catch-all routes with string arrays
* type DocsParams = {
* path: string[];
* };
* ```
*/
export interface SSGParamsLike {
[key: string]: string | string[];
}
/**
* Configuration object for a single static route to be generated.
*
* Each path object contains the parameters needed to render a specific
* instance of a dynamic route at build time.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this path
*
* @example
* ```tsx
* // Single blog post path
* const blogPath: SSGPath<{ slug: string }> = {
* params: { slug: "my-first-post" }
* };
*
* // Product page with multiple params
* const productPath: SSGPath<{ category: string; id: string }> = {
* params: {
* category: "electronics",
* id: "laptop-123"
* }
* };
*
* // Documentation with catch-all route
* const docsPath: SSGPath<{ path: string[] }> = {
* params: { path: ["getting-started", "installation"] }
* };
* ```
*/
export interface SSGPath<Params extends SSGParamsLike = SSGParamsLike> {
params: Params;
}
/**
* Array of static paths to be generated at build time.
*
* This type represents the collection of all route configurations
* that should be pre-rendered for a dynamic route.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for these paths
*
* @example
* ```tsx
* // Array of blog post paths
* const blogPaths: SSGPaths<{ slug: string }> = [
* { params: { slug: "introduction-to-bun" } },
* { params: { slug: "performance-benchmarks" } },
* { params: { slug: "getting-started-guide" } }
* ];
*
* // Mixed parameter types
* const productPaths: SSGPaths<{ category: string; id: string }> = [
* { params: { category: "books", id: "javascript-guide" } },
* { params: { category: "electronics", id: "smartphone-x" } }
* ];
* ```
*/
export type SSGPaths<Params extends SSGParamsLike = SSGParamsLike> = SSGPath<Params>[];
/**
* Props interface for SSG page components.
*
* This interface defines the shape of props that will be passed to your
* static page components during the build process. The `params` object
* contains the route parameters extracted from the URL pattern.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this page
*
* @example
* ```tsx
* // Blog post component props
* interface BlogPageProps extends SSGPageProps<{ slug: string }> {
* // params: { slug: string } is automatically included
* }
*
* // Product page component props
* interface ProductPageProps extends SSGPageProps<{
* category: string;
* id: string;
* }> {
* // params: { category: string; id: string } is automatically included
* }
*
* // Usage in component
* function BlogPost({ params }: BlogPageProps) {
* const { slug } = params; // TypeScript knows slug is a string
* return <h1>Blog post: {slug}</h1>;
* }
* ```
*/
export interface SSGPageProps<Params extends SSGParamsLike = SSGParamsLike> {
params: Params;
}
/**
* React component type for SSG pages that can be statically generated.
*
* This type represents a React component that receives SSG page props
* and can be rendered at build time. The component can be either a regular
* React component or an async React Server Component for advanced use cases
* like data fetching during static generation.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for this page component
*
* @example
* ```tsx
* // Regular synchronous SSG page component
* const BlogPost: SSGPage<{ slug: string }> = ({ params }) => {
* return (
* <article>
* <h1>Blog Post: {params.slug}</h1>
* <p>This content was generated at build time!</p>
* </article>
* );
* };
*
* // Async React Server Component for data fetching
* const AsyncBlogPost: SSGPage<{ slug: string }> = async ({ params }) => {
* // Fetch data during static generation
* const post = await fetchBlogPost(params.slug);
* const author = await fetchAuthor(post.authorId);
*
* return (
* <article>
* <h1>{post.title}</h1>
* <p>By {author.name}</p>
* <div dangerouslySetInnerHTML={{ __html: post.content }} />
* </article>
* );
* };
*
* // Product page with multiple params and async data fetching
* const ProductPage: SSGPage<{ category: string; id: string }> = async ({ params }) => {
* const [product, reviews] = await Promise.all([
* fetchProduct(params.category, params.id),
* fetchProductReviews(params.id)
* ]);
*
* return (
* <div>
* <h1>{product.name}</h1>
* <p>Category: {params.category}</p>
* <p>Price: ${product.price}</p>
* <div>
* <h2>Reviews ({reviews.length})</h2>
* {reviews.map(review => (
* <div key={review.id}>{review.comment}</div>
* ))}
* </div>
* </div>
* );
* };
* ```
*/
export type SSGPage<Params extends SSGParamsLike = SSGParamsLike> = import("react").ComponentType<
SSGPageProps<Params>
>;
/**
* getStaticPaths is Bun's implementation of SSG (Static Site Generation) path determination.
*
* This function is called at your app's build time to determine which
* dynamic routes should be pre-rendered as static pages. It returns an
* array of path parameters that will be used to generate static pages for
* dynamic routes (e.g., [slug].tsx, [category]/[id].tsx).
*
* The function can be either synchronous or asynchronous, allowing you to
* fetch data from APIs, databases, or file systems to determine which paths
* should be statically generated.
*
* @warning These APIs are experimental and might be moved/changed in future releases.
*
* @template Params - The shape of route parameters for the dynamic route
*
* @returns An object containing an array of paths to be statically generated
*
* @example
* ```tsx
* // In pages/blog/[slug].tsx ———————————————————╮
* export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => {
* // Fetch all blog posts from your CMS or API at build time
* const posts = await fetchBlogPosts();
*
* return {
* paths: posts.map((post) => ({
* params: { slug: post.slug }
* }))
* };
* };
*
* // In pages/products/[category]/[id].tsx
* export const getStaticPaths: GetStaticPaths<{
* category: string;
* id: string;
* }> = async () => {
* // Fetch products from database
* const products = await db.products.findMany({
* select: { id: true, category: { slug: true } }
* });
*
* return {
* paths: products.map(product => ({
* params: {
* category: product.category.slug,
* id: product.id
* }
* }))
* };
* };
*
* // In pages/docs/[...path].tsx (catch-all route)
* export const getStaticPaths: GetStaticPaths<{ path: string[] }> = async () => {
* // Read documentation structure from file system
* const docPaths = await getDocumentationPaths('./content/docs');
*
* return {
* paths: docPaths.map(docPath => ({
* params: { path: docPath.split('/') }
* }))
* };
* };
*
* // Synchronous example with static data
* export const getStaticPaths: GetStaticPaths<{ id: string }> = () => {
* const staticIds = ['1', '2', '3', '4', '5'];
*
* return {
* paths: staticIds.map(id => ({
* params: { id }
* }))
* };
* };
* ```
*/
export type GetStaticPaths<Params extends SSGParamsLike = SSGParamsLike> = () => MaybePromise<{
paths: SSGPaths<Params>;
}>;
}
}

View File

@@ -20,7 +20,6 @@
/// <reference path="./deprecated.d.ts" /> /// <reference path="./deprecated.d.ts" />
/// <reference path="./redis.d.ts" /> /// <reference path="./redis.d.ts" />
/// <reference path="./shell.d.ts" /> /// <reference path="./shell.d.ts" />
/// <reference path="./experimental.d.ts" />
/// <reference path="./serve.d.ts" /> /// <reference path="./serve.d.ts" />
/// <reference path="./sql.d.ts" /> /// <reference path="./sql.d.ts" />
/// <reference path="./security.d.ts" /> /// <reference path="./security.d.ts" />

View File

@@ -22,12 +22,6 @@
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
}, },
"peerDependencies": {
"@types/react": "^19"
},
"devDependencies": {
"@types/react": "^19"
},
"scripts": { "scripts": {
"prebuild": "echo $(pwd)", "prebuild": "echo $(pwd)",
"copy-docs": "rm -rf docs && cp -rL ../../docs/ ./docs && find ./docs -type f -name '*.{md,mdx}' -exec sed -i 's/\\$BUN_LATEST_VERSION/'\"${BUN_VERSION#bun-v}\"'/g' {} +", "copy-docs": "rm -rf docs && cp -rL ../../docs/ ./docs && find ./docs -type f -name '*.{md,mdx}' -exec sed -i 's/\\$BUN_LATEST_VERSION/'\"${BUN_VERSION#bun-v}\"'/g' {} +",

View File

@@ -34,7 +34,7 @@ beforeAll(async () => {
TEMP_FIXTURE_DIR = join(TEMP_DIR, "fixture"); TEMP_FIXTURE_DIR = join(TEMP_DIR, "fixture");
try { try {
await $`mkdir -p ${TEMP_FIXTURE_DIR}`; await $`mkdir -p ${TEMP_FIXTURE_DIR}`.quiet();
await cp(FIXTURE_SOURCE_DIR, TEMP_FIXTURE_DIR, { recursive: true }); await cp(FIXTURE_SOURCE_DIR, TEMP_FIXTURE_DIR, { recursive: true });
@@ -42,7 +42,7 @@ beforeAll(async () => {
cd ${BUN_TYPES_PACKAGE_ROOT} cd ${BUN_TYPES_PACKAGE_ROOT}
bun install --no-cache bun install --no-cache
cp package.json package.json.backup cp package.json package.json.backup
`; `.quiet();
const pkg = await Bun.file(BUN_TYPES_PACKAGE_JSON_PATH).json(); const pkg = await Bun.file(BUN_TYPES_PACKAGE_JSON_PATH).json();
@@ -58,10 +58,9 @@ beforeAll(async () => {
cd ${TEMP_FIXTURE_DIR} cd ${TEMP_FIXTURE_DIR}
bun add bun-types@${BUN_TYPES_TARBALL_NAME} bun add bun-types@${BUN_TYPES_TARBALL_NAME}
rm ${BUN_TYPES_TARBALL_NAME} rm ${BUN_TYPES_TARBALL_NAME}
`; `.quiet();
const atTypesBunDir = join(TEMP_FIXTURE_DIR, "node_modules", "@types", "bun"); const atTypesBunDir = join(TEMP_FIXTURE_DIR, "node_modules", "@types", "bun");
console.log("Making tree", atTypesBunDir);
await mkdir(atTypesBunDir, { recursive: true }); await mkdir(atTypesBunDir, { recursive: true });
await makeTree(atTypesBunDir, { await makeTree(atTypesBunDir, {
@@ -195,140 +194,7 @@ async function diagnose(
}; };
} }
const expectedEmptyInterfacesWhenNoDOM = new Set([ const expectedEmptyInterfacesWhenNoDOM = new Set(["ThisType"]);
"ThisType",
"Document",
"DataTransfer",
"StyleMedia",
"Element",
"DocumentFragment",
"HTMLElement",
"HTMLAnchorElement",
"HTMLAreaElement",
"HTMLAudioElement",
"HTMLBaseElement",
"HTMLBodyElement",
"HTMLBRElement",
"HTMLButtonElement",
"HTMLCanvasElement",
"HTMLDataElement",
"HTMLDataListElement",
"HTMLDetailsElement",
"HTMLDialogElement",
"HTMLDivElement",
"HTMLDListElement",
"HTMLEmbedElement",
"HTMLFieldSetElement",
"HTMLFormElement",
"HTMLHeadingElement",
"HTMLHeadElement",
"HTMLHRElement",
"HTMLHtmlElement",
"HTMLIFrameElement",
"HTMLImageElement",
"HTMLInputElement",
"HTMLModElement",
"HTMLLabelElement",
"HTMLLegendElement",
"HTMLLIElement",
"HTMLLinkElement",
"HTMLMapElement",
"HTMLMetaElement",
"HTMLMeterElement",
"HTMLObjectElement",
"HTMLOListElement",
"HTMLOptGroupElement",
"HTMLOptionElement",
"HTMLOutputElement",
"HTMLParagraphElement",
"HTMLParamElement",
"HTMLPreElement",
"HTMLProgressElement",
"HTMLQuoteElement",
"HTMLSlotElement",
"HTMLScriptElement",
"HTMLSelectElement",
"HTMLSourceElement",
"HTMLSpanElement",
"HTMLStyleElement",
"HTMLTableElement",
"HTMLTableColElement",
"HTMLTableDataCellElement",
"HTMLTableHeaderCellElement",
"HTMLTableRowElement",
"HTMLTableSectionElement",
"HTMLTemplateElement",
"HTMLTextAreaElement",
"HTMLTimeElement",
"HTMLTitleElement",
"HTMLTrackElement",
"HTMLUListElement",
"HTMLVideoElement",
"HTMLWebViewElement",
"SVGElement",
"SVGSVGElement",
"SVGCircleElement",
"SVGClipPathElement",
"SVGDefsElement",
"SVGDescElement",
"SVGEllipseElement",
"SVGFEBlendElement",
"SVGFEColorMatrixElement",
"SVGFEComponentTransferElement",
"SVGFECompositeElement",
"SVGFEConvolveMatrixElement",
"SVGFEDiffuseLightingElement",
"SVGFEDisplacementMapElement",
"SVGFEDistantLightElement",
"SVGFEDropShadowElement",
"SVGFEFloodElement",
"SVGFEFuncAElement",
"SVGFEFuncBElement",
"SVGFEFuncGElement",
"SVGFEFuncRElement",
"SVGFEGaussianBlurElement",
"SVGFEImageElement",
"SVGFEMergeElement",
"SVGFEMergeNodeElement",
"SVGFEMorphologyElement",
"SVGFEOffsetElement",
"SVGFEPointLightElement",
"SVGFESpecularLightingElement",
"SVGFESpotLightElement",
"SVGFETileElement",
"SVGFETurbulenceElement",
"SVGFilterElement",
"SVGForeignObjectElement",
"SVGGElement",
"SVGImageElement",
"SVGLineElement",
"SVGLinearGradientElement",
"SVGMarkerElement",
"SVGMaskElement",
"SVGMetadataElement",
"SVGPathElement",
"SVGPatternElement",
"SVGPolygonElement",
"SVGPolylineElement",
"SVGRadialGradientElement",
"SVGRectElement",
"SVGSetElement",
"SVGStopElement",
"SVGSwitchElement",
"SVGSymbolElement",
"SVGTextElement",
"SVGTextPathElement",
"SVGTSpanElement",
"SVGUseElement",
"SVGViewElement",
"Text",
"TouchList",
"WebGLRenderingContext",
"WebGL2RenderingContext",
"TrustedHTML",
"MediaStream",
"MediaSource",
]);
function checkForEmptyInterfaces(program: ts.Program) { function checkForEmptyInterfaces(program: ts.Program) {
const empties = new Set<string>(); const empties = new Set<string>();
@@ -385,8 +251,6 @@ function checkForEmptyInterfaces(program: ts.Program) {
afterAll(async () => { afterAll(async () => {
if (TEMP_DIR) { if (TEMP_DIR) {
console.log(TEMP_DIR);
if (Bun.env.TYPES_INTEGRATION_TEST_KEEP_TEMP_DIR === "true") { if (Bun.env.TYPES_INTEGRATION_TEST_KEEP_TEMP_DIR === "true") {
console.log(`Keeping temp dir ${TEMP_DIR}/fixture for debugging`); console.log(`Keeping temp dir ${TEMP_DIR}/fixture for debugging`);
await cp(TSCONFIG_SOURCE_PATH, join(TEMP_DIR, "fixture", "tsconfig.json")); await cp(TSCONFIG_SOURCE_PATH, join(TEMP_DIR, "fixture", "tsconfig.json"));
@@ -515,13 +379,13 @@ describe("@types/bun integration test", () => {
expect(emptyInterfaces).toEqual(expectedEmptyInterfacesWhenNoDOM); expect(emptyInterfaces).toEqual(expectedEmptyInterfacesWhenNoDOM);
expect(diagnostics).toEqual([ expect(diagnostics).toEqual([
// This is expected because we, of course, can't check that our tsx file is passing // // This is expected because we, of course, can't check that our tsx file is passing
// when tsx is turned off... // // when tsx is turned off...
{ // {
"code": 17004, // "code": 17004,
"line": "[slug].tsx:17:10", // "line": "[slug].tsx:17:10",
"message": "Cannot use JSX unless the '--jsx' flag is provided.", // "message": "Cannot use JSX unless the '--jsx' flag is provided.",
}, // },
]); ]);
}); });
@@ -564,7 +428,6 @@ describe("@types/bun integration test", () => {
"WebGLUniformLocation", "WebGLUniformLocation",
"WebGLVertexArrayObject", "WebGLVertexArrayObject",
"WebGLVertexArrayObjectOES", "WebGLVertexArrayObjectOES",
"TrustedHTML",
]), ]),
); );
expect(diagnostics).toEqual([ expect(diagnostics).toEqual([

View File

@@ -1,38 +1,42 @@
import { join } from "path"; // This page test can return once we implement ssg/ssr/rsc again
import { expectType } from "./utilities";
// we're just checking types here really // import { join } from "path";
declare function markdownToJSX(markdown: string): React.ReactNode; // import { expectType } from "./utilities";
type Params = { // // we're just checking types here really
slug: string; // declare function markdownToJSX(markdown: string): React.ReactNode;
};
const Index: Bun.__experimental.SSGPage<Params> = async ({ params }) => { // type Params = {
expectType(params.slug).is<string>(); // slug: string;
// };
const content = await Bun.file(join(process.cwd(), "posts", params.slug + ".md")).text(); // const Index: Bun.__experimental.SSGPage<Params> = async ({ params }) => {
const node = markdownToJSX(content); // expectType(params.slug).is<string>();
return <div>{node}</div>; // const content = await Bun.file(join(process.cwd(), "posts", params.slug + ".md")).text();
}; // const node = markdownToJSX(content);
expectType(Index.displayName).is<string | undefined>(); // return <div>{node}</div>;
// };
export default Index; // expectType(Index.displayName).is<string | undefined>();
export const getStaticPaths: Bun.__experimental.GetStaticPaths<Params> = async () => { // export default Index;
const glob = new Bun.Glob("**/*.md");
const postsDir = join(process.cwd(), "posts");
const paths: Bun.__experimental.SSGPaths<Params> = [];
for (const file of glob.scanSync({ cwd: postsDir })) { // export const getStaticPaths: Bun.__experimental.GetStaticPaths<Params> = async () => {
const slug = file.replace(/\.md$/, ""); // const glob = new Bun.Glob("**/*.md");
// const postsDir = join(process.cwd(), "posts");
// const paths: Bun.__experimental.SSGPaths<Params> = [];
paths.push({ // for (const file of glob.scanSync({ cwd: postsDir })) {
params: { slug }, // const slug = file.replace(/\.md$/, "");
});
}
return { paths }; // paths.push({
}; // params: { slug },
// });
// }
// return { paths };
// };
export {};