close
Skip to content

TypeScript: migrate annotations package to TS#70602

Merged
manzoorwanijk merged 17 commits into
WordPress:trunkfrom
kushagra-goyal-14:try/migrate-annotations-ts
Apr 9, 2026
Merged

TypeScript: migrate annotations package to TS#70602
manzoorwanijk merged 17 commits into
WordPress:trunkfrom
kushagra-goyal-14:try/migrate-annotations-ts

Conversation

@kushagra-goyal-14
Copy link
Copy Markdown
Contributor

What?

Part of #67691

Migrating the annotations package to TypeScript.

Why?

To enhance DX and add type safety.

How?

By porting the code and tests to TypeScript.

Testing Instructions

Typecheck and unit tests.

@kushagra-goyal-14 kushagra-goyal-14 marked this pull request as ready for review July 3, 2025 11:14
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jul 3, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: kushagra-goyal-14 <kush123@git.wordpress.org>
Co-authored-by: manzoorwanijk <manzoorwanijk@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@t-hamano t-hamano mentioned this pull request Jul 4, 2025
39 tasks
@t-hamano t-hamano added [Type] Code Quality Issues or PRs that relate to code quality [Feature] Annotations Adding annotation functionality labels Jul 4, 2025
Comment thread packages/annotations/src/block/index.ts Outdated
Comment on lines +19 to +20
const addAnnotationClassName = ( OriginalComponent: any ) => {
return ( withSelect as any )(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would prefer to avoid these two any here, which means, we probably should first convert withSelect to typescript.

@manzoorwanijk
Copy link
Copy Markdown
Member

What is the status here?

@kushagra-goyal-14
Copy link
Copy Markdown
Contributor Author

Hi @manzoorwanijk, I made some changes since it seems withSelect has been migrated. Can you please review them?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Migrates the @wordpress/annotations package implementation and tests to TypeScript as part of the broader “convert packages to TS” effort, adding explicit types for annotations, store actions/state, and format registration.

Changes:

  • Adds a new TS project config for packages/annotations and wires it into the root TS project references.
  • Ports annotations store (actions/reducer/selectors) and related runtime modules (format + block filter) to TypeScript and introduces shared types.ts.
  • Updates docs autogen tokens to point at the new .ts sources.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tsconfig.json Adds packages/annotations as a TS project reference.
packages/annotations/tsconfig.json New package-level TS config (rootDir, declarationDir, references).
packages/annotations/src/types.ts Introduces core annotation/store/format TypeScript types.
packages/annotations/src/store/actions.ts Ports store actions to TS, adds typed action union usage.
packages/annotations/src/store/reducer.ts Ports reducer to TS and adds typed helpers/validation.
packages/annotations/src/store/selectors.ts Adds TS types for selector inputs/outputs and tightens JSDoc.
packages/annotations/src/store/index.ts Keeps store registration; minor JSDoc cleanup.
packages/annotations/src/store/constants.ts Minor JSDoc cleanup.
packages/annotations/src/store/test/reducer.ts Updates tests for TS types and stricter action shapes.
packages/annotations/src/index.ts New TS entrypoint importing format/block side effects and exporting store.
packages/annotations/src/format/index.ts TS adjustment for registering the annotation rich-text format.
packages/annotations/src/format/annotation.ts Adds RichTextValue typing + TS-safe handling in format utilities.
packages/annotations/src/block/index.ts Ports block filter to TS and uses the exported store in select.
docs/reference-guides/data/data-core-annotations.md Updates autogen tokens to reference .ts sources.
Comments suppressed due to low confidence (1)

packages/annotations/src/format/index.ts:13

  • registerFormatType is being called with settings as any, which defeats the goal of the TS migration. It looks like the annotation format object is missing required properties from the WPFormat shape (notably interactive and object); adding them to the format definition (and to the AnnotationFormat type) should allow removing this cast.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,20 @@
{
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

The tsconfig files in this repo typically include the $schema field for editor/validation support. Consider adding it here for consistency with other package tsconfigs (e.g. packages/keycodes/tsconfig.json).

Suggested change
{
{
"$schema": "https://json.schemastore.org/tsconfig",

Copilot uses AI. Check for mistakes.
* The `block` attribute refers to a block ID that needs to be annotated.
* `isBlockAnnotation` controls whether or not the annotation is a block
* annotation. The `source` is the source of the annotation, this will be used
* to identity groups of annotations.
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

The JSDoc says "to identity groups of annotations" which reads like a typo/grammar issue. This should likely be "to identify groups of annotations".

Suggested change
* to identity groups of annotations.
* to identify groups of annotations.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +59
if ( selector === 'range' ) {
(
action as Extract< AnnotationAction, { type: 'ANNOTATION_ADD' } >
).range = range as WPAnnotationRange;
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

range is declared as WPAnnotationRange | null in AddAnnotationParameters, but this code force-casts it to WPAnnotationRange and assigns it even when it may be null. This weakens type safety and can hide invalid dispatches; consider only setting action.range when range is non-null (or update the AnnotationAction type to reflect null if it's intentionally allowed).

Suggested change
if ( selector === 'range' ) {
(
action as Extract< AnnotationAction, { type: 'ANNOTATION_ADD' } >
).range = range as WPAnnotationRange;
if ( selector === 'range' && range !== null ) {
(
action as Extract< AnnotationAction, { type: 'ANNOTATION_ADD' } >
).range = range;

Copilot uses AI. Check for mistakes.
attributes: {
className: string;
id: string;
};
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

AnnotationFormat doesn't include the interactive and object properties that @wordpress/rich-text's registerFormatType expects for a WPFormat, which is likely why settings as any is needed in format/index.ts. Consider adding these fields (e.g. as booleans) so the format object can be passed to registerFormatType without an unsafe cast.

Suggested change
};
};
interactive: boolean;
object: boolean;

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +20
* @property {number} start The offset where the annotation should start.
* @property {number} end The offset where the annotation should end.
*/

/**
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This standalone JSDoc block with only @property tags looks like a leftover from the old @typedef WPAnnotationRange and is no longer attached to any symbol (since WPAnnotationRange is now a TS interface). Consider removing it to avoid confusing doc generation / JSDoc linting.

Suggested change
* @property {number} start The offset where the annotation should start.
* @property {number} end The offset where the annotation should end.
*/
/**

Copilot uses AI. Check for mistakes.
@kushagra-goyal-14
Copy link
Copy Markdown
Contributor Author

@manzoorwanijk I have made the changes as per the Copilot review. Can you please re-check? Thanks

Copy link
Copy Markdown
Member

@manzoorwanijk manzoorwanijk left a comment

Choose a reason for hiding this comment

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

This looks good. I have some suggestions for further improvements.

Comment thread packages/annotations/tsconfig.json Outdated
Comment on lines +3 to +6
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types"
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We don't need these overrides.

Suggested change
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types"
},

Comment thread packages/annotations/tsconfig.json Outdated
Comment on lines +12 to +19
],
"include": [ "src/**/*" ],
"exclude": [
"src/**/*.test.ts",
"src/**/*.test.tsx",
"src/**/test/**/*.ts",
"src/**/test/**/*.tsx"
]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We don't need these overrides either

Suggested change
],
"include": [ "src/**/*" ],
"exclude": [
"src/**/*.test.ts",
"src/**/*.test.tsx",
"src/**/test/**/*.ts",
"src/**/test/**/*.tsx"
]
]

selector: 'range',
range: {
start: 'not a number',
start: 'not a number' as any,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's better to use // @ts-expect-error in such cases with a comment explaining why.

range: {
start: 100,
end: 'not a number',
end: 'not a number' as any,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here about using // @ts-expect-error.

Comment thread packages/annotations/src/types.ts Outdated
/**
* Represents a range in text content.
*/
export interface WPAnnotationRange {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let us remove the WP prefix here.

Comment thread packages/annotations/src/types.ts Outdated
/**
* Base annotation interface.
*/
export interface WPAnnotation {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need of WP prefix.

Comment thread tsconfig.json Outdated
"references": [
{ "path": "bin" },
{ "path": "packages/a11y" },
{ "path": "packages/annotations" },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let us place it in the correct place in alphabetical order.

@manzoorwanijk manzoorwanijk requested a review from Copilot April 7, 2026 17:51
Copy link
Copy Markdown
Member

@manzoorwanijk manzoorwanijk left a comment

Choose a reason for hiding this comment

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

We haven't added the types field to package.json here. We also need to add it to the exports['.'] field there.

@manzoorwanijk
Copy link
Copy Markdown
Member

@claude Review this

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 16 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

packages/annotations/src/store/selectors.ts:76

  • In __experimentalGetAnnotationsForRichText, range is typed as AnnotationRange | null | undefined (since Annotation.range is optional/nullable), but the code spreads it ({ ...range, ...other }). With strict TS this will error because object spread requires a non-null object type. Consider narrowing in the filter (e.g., ensure annotation.range is present) or otherwise making range non-null before spreading so this selector typechecks and matches the reducer invariant (range annotations always have a range).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/annotations/src/types.ts Outdated
Comment on lines +59 to +61
export interface AnnotationsState {
[ blockClientId: string ]: Annotation[];
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

AnnotationsState is currently defined with a string index signature returning Annotation[], which implies every key lookup returns an array even when the blockClientId key is missing. The rest of the code already treats missing keys as undefined (e.g. state?.[ blockClientId ] ?? []), so the state type is unsound. Consider changing it to something like Record<string, Annotation[] | undefined> (or Partial<Record<string, Annotation[]>>) to reflect runtime behavior and avoid incorrect assumptions in consumers.

Suggested change
export interface AnnotationsState {
[ blockClientId: string ]: Annotation[];
}
export type AnnotationsState = Partial< Record< string, Annotation[] > >;

Copilot uses AI. Check for mistakes.
@manzoorwanijk
Copy link
Copy Markdown
Member

Let us make CI happy and please mention me when it's ready again. Thank you for your contributions.

…xperimentalGetAnnotations to filter out undefined values in selectors.ts
@kushagra-goyal-14
Copy link
Copy Markdown
Contributor Author

Hi @manzoorwanijk, I have made the changes, just waiting for the CI.

Copy link
Copy Markdown
Member

@manzoorwanijk manzoorwanijk left a comment

Choose a reason for hiding this comment

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

This looks good now. Thank you.

@manzoorwanijk manzoorwanijk merged commit 8969243 into WordPress:trunk Apr 9, 2026
40 checks passed
@github-actions github-actions Bot added this to the Gutenberg 23.0 milestone Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Annotations Adding annotation functionality [Type] Code Quality Issues or PRs that relate to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants