Skip to content

Conversation

@colinrotherham
Copy link
Contributor

Great work on Prettier v3 🙌

Hope this PR is welcome, but I've added JSDoc + tsconfig.json to export type declarations

I followed the link in the Prettier 3.0: Hello, ECMAScript Modules! blog post after realising that the Prettier sync APIs would still be needed to avoid Nunjucks template changes for asynchronous rendering 😣

If you still need sync APIs, you can try @prettier/sync

I'd be happy to make any tweaks, and wasn't sure if committing the types would be preferred

Closes: #8

@fisker
Copy link
Member

fisker commented Jul 11, 2023

Thanks for working on this. Can it be done by adding a .d.ts file?

@colinrotherham
Copy link
Contributor Author

Thanks for working on this. Can it be done by adding a .d.ts file?

Yeah course, I've pushed up a new .gitignore to show them:

  1. Added index.d.cts type declarations for .cjs extension files
  2. Added index.d.cts.map type declaration map to link back to source

Declaration Map
Generates a source map for .d.ts files which map back to the original .ts source file. This will allow editors such as VS Code to go to the original .ts file when using features like Go to Definition.

I've used import('prettier') in the JSDoc to make sure the existing type declarations are reused when built

Imports types from Prettier

index.d.cts Outdated
Comment on lines 43 to 54
declare const PRETTIER_ASYNC_FUNCTIONS: readonly [
"formatWithCursor",
"format",
"check",
"resolveConfig",
"resolveConfigFile",
"clearConfigCache",
"getFileInfo",
"getSupportInfo",
];
declare const PRETTIER_STATIC_PROPERTIES: readonly ["version", "util", "doc"];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with types, but why are these needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're not publicly exported, but I've added /** @type {const} */ to these two:

PRETTIER_ASYNC_FUNCTIONS
PRETTIER_STATIC_PROPERTIES

When a function is called or property is accessed that doesn't exist (or renamed) it'll validate against:

FunctionName in typeof PRETTIER_ASYNC_FUNCTIONS[number]
PropertyName in typeof PRETTIER_STATIC_PROPERTIES[number]

Otherwise we'd have to duplicate them in quite a few places:

FunctionName extends "formatWithCursor" | "format" | "check" | "resolveConfig" | "resolveConfigFile" | "clearConfigCache" | "getFileInfo" | "getSupportInfo"
Property extends "version" | "util" | "doc"

These consts are used to populate the functions/properties available in editors:

Prettier available functions and properties

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate they're not needed externally so tried adding @internal

But when setting tsconfig.json "stripInternal": true it didn't work due to:

One of the downsides to using the compiler with JSDoc 😔

index.d.cts Outdated
@@ -0,0 +1,54 @@
declare const _exports: PrettierSync;
export = _exports;
export type Prettier = typeof import("prettier");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to do something like

import type Prettier from "prettier";

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me look into it

It's the tsc compiler automatically exporting @typedef by default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about hand-writing code like this

import type {
  version,
  util,
  doc,
  formatWithCursor,
  format,
  check,
  resolveConfig,
  resolveConfigFile,
  getFileInfo,
  getSupportInfo,
} from "prettier";

type SynchronizedPrettier = {
  // Prettier static properties
  version: typeof version;
  util: typeof util;
  doc: typeof doc;

  // Prettier functions
  formatWithCursor: Awaited<ReturnType<typeof formatWithCursor>>;
  format: Awaited<ReturnType<typeof format>>;
  check: Awaited<ReturnType<typeof check>>;
  resolveConfig: Awaited<ReturnType<typeof resolveConfig>>;
  resolveConfigFile: Awaited<ReturnType<typeof resolveConfigFile>>;
  getFileInfo: Awaited<ReturnType<typeof getFileInfo>>;
  getSupportInfo: Awaited<ReturnType<typeof getSupportInfo>>;
};

Copy link
Contributor Author

@colinrotherham colinrotherham Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entirely up to you 😊

With JSDoc and checkJs enabled (without switching to TypeScript) you'll be able to use code completion, see documentation in tooltips, and spot and errors and warnings as-you-type—in this repo too

Plus it lets the compiler validate that type declarations are correct when prettier "./src/index.d.ts" types change without having to keep types synchronised between repos by hand

tsconfig.json

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true
  }
}

I'd be more than happy if you used this PR for guidance to add them manually 👍

Let me know if you'd like anything splitting out

Update: Split out manually in 7d922c2

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './index.cjs' is not defined by "exports" in /path/to/example/node_modules/@prettier/sync/package.json imported from /path/to/example/index.mjs
@fisker
Copy link
Member

fisker commented Jul 11, 2023

I have no experience with type declarations.

@SimenB Can you help review?

@colinrotherham
Copy link
Contributor Author

@fisker I've removed all the unnecessary autogenerated lines from index.d.cts

We're left with the good stuff like Awaited<ReturnType<Prettier[FunctionName]>>

But I've kept the tsconfig.json and JSDoc comments so you get type checking locally too

@colinrotherham colinrotherham changed the title Build type declarations from JSDoc comments Check type declarations with JSDoc comments Jul 17, 2023
@fisker fisker merged commit 253edba into prettier:main Jul 17, 2023
@fisker
Copy link
Member

fisker commented Jul 17, 2023

@colinrotherham
Copy link
Contributor Author

Brilliant, thanks @fisker

Just a reminder that manually adding the types without a type declaration map means editor and IDE "Go to definition" will jump to the types rather than the original Prettier source code, should you want that in future

Glad I could help though, appreciate it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export TS types

3 participants