From 57f702f7656e6fc03873f8121480c321b2f44c8c Mon Sep 17 00:00:00 2001 From: Dom Porada Date: Wed, 21 Jan 2026 18:07:32 +0100 Subject: [PATCH] Include available `printers` in plugin type declarations (#18706) Co-authored-by: fisker --- changelog_unreleased/api/18706.md | 15 +++++++++++ scripts/build/build-types.js | 45 ++++++++++++++++++++++++++----- tests/dts/unit/cases/parsers.ts | 4 +++ 3 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 changelog_unreleased/api/18706.md diff --git a/changelog_unreleased/api/18706.md b/changelog_unreleased/api/18706.md new file mode 100644 index 000000000..fc7009e78 --- /dev/null +++ b/changelog_unreleased/api/18706.md @@ -0,0 +1,15 @@ +#### Include available `printers` in plugin type declarations (#18706 by @porada) + + +```ts +// Input +import * as prettierPluginEstree from "prettier/plugins/estree"; + +// Prettier stable +// Property 'printers' does not exist on type 'typeof import("prettier/plugins/estree")'. ts(2339) +prettierPluginEstree.printers.estree; //=> any + +// Prettier main +prettierPluginEstree.printers.estree; //=> Printer +prettierPluginEstree.printers["estree-json"]; //=> Printer +``` diff --git a/scripts/build/build-types.js b/scripts/build/build-types.js index 86f1c9ef0..95b329b73 100644 --- a/scripts/build/build-types.js +++ b/scripts/build/build-types.js @@ -36,15 +36,19 @@ async function buildPluginTypes({ packageConfig, file: { input, output } }) { ); const plugin = pluginModule.default ?? pluginModule; const parserNames = Object.keys(plugin.parsers ?? {}); + const printerNames = Object.keys(plugin.printers ?? {}); + const typesImportPath = + packageConfig.packageName === "prettier" ? "../index.js" : "prettier"; - // We only add `parsers` to types file, printers should not be used alone - // For `estree` plugin, we just export an empty object to ensure it treated as a module - const code = - parserNames.length === 0 - ? "export {};" - : outdent` - import { Parser } from "${packageConfig.packageName === "prettier" ? "../index.js" : "prettier"}"; + // Export available `parsers` and `printers` as types. If none are available, + // export an empty module object to ensure the file is treated as a module + const types = []; + const declarations = []; + if (parserNames.length > 0) { + types.push("Parser"); + declarations.push( + outdent` export declare const parsers: { ${parserNames .map( @@ -53,6 +57,33 @@ async function buildPluginTypes({ packageConfig, file: { input, output } }) { ) .join("\n")} }; + `, + ); + } + + if (printerNames.length > 0) { + types.push("Printer"); + declarations.push( + outdent` + export declare const printers: { + ${printerNames + .map( + (printerName) => + `${" ".repeat(2)}${toPropertyKey(printerName)}: Printer;`, + ) + .join("\n")} + }; + `, + ); + } + + const code = + declarations.length === 0 + ? "export {};" + : outdent` + import { ${types.join(", ")} } from "${typesImportPath}"; + + ${declarations.join("\n\n")} `; await writeFile( diff --git a/tests/dts/unit/cases/parsers.ts b/tests/dts/unit/cases/parsers.ts index 725f6022c..9a690607f 100644 --- a/tests/dts/unit/cases/parsers.ts +++ b/tests/dts/unit/cases/parsers.ts @@ -1,4 +1,5 @@ import * as prettier from "../../../../dist/prettier/index.js"; +import { expectType } from "ts-expect"; import * as prettierPluginEstree from "../../../../dist/prettier/plugins/estree.js"; import * as prettierPluginBabel from "../../../../dist/prettier/plugins/babel.js"; @@ -104,3 +105,6 @@ prettier.format("hello world", { prettierPluginYaml, ], }); + +expectType(prettierPluginEstree.printers.estree); +expectType(prettierPluginEstree.printers["estree-json"]);