-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor to use TypeScript @import
JSDoc tags
#2498
Conversation
Previously we used `@typedef` tags to simulate type imports. The problem is that are not really imports. They define and export a new type. We now use `@import` introduced by TypeScript 5.5 to actually import types. The pattern using `@typedef` is still used in index files to export types. This change also replaces the type casting inside MDX files with definitions of the `Props` types. This also replaces usage of the global `JSX` namespace with proper types. For TypeScript<5.1 the correct return type of React components is `ReactElement`, for Preact `VNode`. For TypeScript>=5.1, the correct return type for React components is `ReactNode`, for Preact `ComponentChildren`.
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
* @import { | ||
MdxJsxAttribute, | ||
MdxJsxAttributeValueExpression, | ||
MdxJsxExpressionAttribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using asterisks for multiline imports caused problems, but not in the TypeScript playground. I’m looking into this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d work around it by not wrapping 🤷♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that. It would be ok’ish for this line, but some others would become extremely long. I prefer to keep it like this TBH, keeping the max length at approximately what we use for Prettier.
* @import { | ||
MdxJsxAttribute, | ||
MdxJsxAttributeValueExpression, | ||
MdxJsxExpressionAttribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d work around it by not wrapping 🤷♂️
@@ -601,7 +601,7 @@ function ErrorFallback(properties) { | |||
/** | |||
* @param {DisplayProperties} properties | |||
* Properties. | |||
* @returns {JSX.Element} | |||
* @returns {ReactNode} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
better in separate PRs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. One thing let to another. IMO this is fine to keep as-is now.
docs/blog/index.mdx
Outdated
{/** | ||
* @typedef Props | ||
* @property {Item} navigationTree | ||
*/} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not 100% on this style? I’d lean to:
{
/**
* @import {Item} from '../_component/sort.js'
*/
/**
* @typedef Props
* @property {Item} navigationTree
*/
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have given this some thought while working on MDX language server. The indentation of this style feels a bit weird IMO.
{/**
* @import {Component} from 'react'
* @import {AvatarProps} from './avatar.js'
*/}
{/**
* @typedef Comonents
* @property {Component<AvatarProps>} avatar
*/}
{/**
* @typedef Props
* @property {Comonents} components
*/}
{/**
* Some description
*
* @param {unknown} parameter
* @returns {undefined}
*/}
export function someFunction(parameter) {}
# Hello
<Avatar />
But combining all comments, or combining comments arbritratily, with or without indentation feels even more weird to me.
{
/**
* @import {Component} from 'react'
* @import {AvatarProps} from './avatar.js'
*/
/**
* @typedef Comonents
* @property {Component<AvatarProps>} avatar
*/
/**
* @typedef Props
* @property {Comonents} components
*/
}
{/**
* Some description
*
* @param {unknown} parameter
* @returns {undefined}
*/}
export function someFunction(parameter) {}
# Hello
<Avatar />
It feels a bit similar to whether or not to group typedefs in a single comment.
So far I feel best about putting each typedef in a separate comment, and each comment in a separate mdxFlowExpression
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I feel quite strongly that entering/exiting JS each time is ugly.
And that if you’d put something in there (like a jsx element), that it would be indented 🤔
I’m fine to different typedefs in different comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I feel quite strongly that entering/exiting JS each time is ugly.
I don’t really mind either style for typedefs. For function docs I would find it weird to combine though, but that’s not applicable in this particular case.
Another thing is that commenting is based on {/*
and */}
delimiters. Though I don’t think it makes sense to uncomment jsdoc comments.
And that if you’d put something in there (like a jsx element), that it would be indented 🤔
That makes perfect sense. This also reminds me that it’s possible to have multiple comments in one a flow expression, but just one JS expression. JSDoc has meaning, which makes me lean towards preferring one doc per flow expression again. But having the types grouped using one flow expression is also kind of nice.
Anyway, these are all just nitty details. I’ll adjust them to use one MDX flow expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For function docs I would find it weird to combine though, but that’s not applicable in this particular case.
Can you clarify what you dislike/like with examples?
Though I don’t think it makes sense to uncomment jsdoc comments.
Agreed. These things are more like type annotations, which currently use special comments, because that’s what’s possible now.
This also reminds me that it’s possible to have multiple comments in one a flow expression, but just one JS expression. JSDoc has meaning, which makes me lean towards preferring one doc per flow expression again. But having the types grouped using one flow expression is also kind of nice.
Right, right, I was thinking about that at first too, but then there’s a difference: these are allowed to be empty! And comments are deemed empty here too. 0 or more empty is still empty. So, zero-or-more empty, then 0-1 expression.
To clarify, some examples of what I think looks good.
Regular comment:
# hi
{/* just a smol comment */}
hello
More complex expression:
# hi
{
(function () {
return 1
})()
}
hello
One JSDoc:
{
/**
* @import {foo} from 'bar'
*/
}
# hi
hello
Multi JSDoc:
{
/**
* @import {foo} from 'bar'
*/
/**
* @typedef Options
* @property {number} something
*/
}
# hi
hello
Multi JSDoc and expression:
# hi
{
/**
* @import {foo} from 'bar'
*/
/**
* @typedef Options
* @property {number} something
*/
(function () {
return 1
})()
}
hello
Also, was just thinking about how do-expressions will be nice!
{
do {
if (loggedIn) {
<LogoutButton />
} else {
<LoginButton />
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify what you dislike/like with examples?
If there are multiple exports with JSDoc annotations, It feels weird to me to merge the mdx flow expression the typedefs with that of the JSDoc of the first export.
{
/**
* @typedef Props
* @property {string} whatever
*/
/**
* @param {string} arg
* @returns undefined
*/
}
export function someExport(arg) {}
{
/**
* @param {string} arg
* @returns undefined
*/
}
export function anotherExport(arg) {}
Also, was just thinking about how do-expressions will be nice!
Yes, that would be so nice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I can see this. But that feels like an edge case to me, induced because we allow export
statements directly in markdown 🤔
I’m fine with breaking it like:
{
/**
* @import {foo} from 'bar'
*/
/**
* @typedef Options
* @property {number} something
*/
}
{
/**
* @param {string} arg
* @returns {undefined}
*/
}
export function someExport(arg) {}
* @typedef {import('./lib/evaluate.js').EvaluateOptions} EvaluateOptions | ||
* @typedef {import('./lib/run.js').RunOptions} RunOptions | ||
* @typedef {import('./lib/util/resolve-evaluate-options.js').EvaluateOptions} EvaluateOptions | ||
* @typedef {import('./lib/util/resolve-evaluate-options.js').RunOptions} RunOptions | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like an index.d.ts
, as it has export type {} from
, here it would get rid of the typedef/type alias https://github.com/rehypejs/rehype-document/blob/main/index.d.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m working on a follow-up PR where I think this is better discussed. I do agree export {} from
is an improvement over a typedef.
* @typedef Props | ||
* @property {Item} navigationTree | ||
*/ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
* @typedef Props | ||
* @property {Item} navigationTree | ||
*/ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like this it’s also more similar to frontmatter 🤔
@import
JSDoc tags@import
JSDoc tags
In this PR, I saw the existing code:
I think we can now change, and recommend |
Thanks :) |
Initial checklist
Description of changes
Previously we used
@typedef
tags to simulate type imports. The problem is that are not really imports. They define and export a new type. We now use@import
introduced by TypeScript 5.5 to actually import types.The pattern using
@typedef
is still used in index files to export types.This change also replaces the type casting inside MDX files with definitions of the
Props
types.This also replaces usage of the global
JSX
namespace with proper types. For TypeScript<5.1 the correct return type of React components isReactElement
, for PreactVNode
. For TypeScript>=5.1, the correct return type for React components isReactNode
, for PreactComponentChildren
.ReactElement
/VNode
and are compatible with TypeScript>=5.1. This is why those are used for public facing APIs, butReactNode
/ComponentChildren
is used for internal components.