-
Notifications
You must be signed in to change notification settings - Fork 4
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
feat: enhance types #18
Conversation
@aduth checkout this file, I typed everything like this and then ported it back into https://github.com/johnhooks/hpq/blob/172fec770524b0b10ed5a2d3e0ff1fd427740633/src/index.ts |
I'm still learning about type MatcherFn = (node: Element) => string|undefined;
type MatcherObj = Record<string, MatcherFn>;
type Matcher = MatcherFn | MatcherObj; Does a |
Thanks for the quick turnaround on the pull request @johnhooks ! I might not be able to take a deep dive on this until the weekend, and shamefully I have to admit that it's been a while since the last major update to this library, so I'm having to refamiliarize myself with it as well! A couple quick comments to what you've surfaced:
|
@aduth thanks! I'm excited to help.
The library seems simple, though it is actually hard to know exactly what is being accessed when the matchers are defined. I am willing to take some time and get it right. And would be happy to help maintain a TS version.
I agree, there should be a way to infer the return type. It might take a little refactoring to make it work.
I for one would support ESM only, that shouldn't affect the largest dependent of this package, Gutenberg. Using It's really cool that this little library is used deep down in the core of Gutenberg. And it's obviously doing a great job because it was able to just sit for four years without any issues! |
cada4ac
to
3a60f96
Compare
Was looking if there might be a way to infer the return type based on the input. Definitely challenging with the overloaded signature. This seems to look okay at a glance, though unsure yet how well it could be ported back to JSDoc: |
That looks really good to me. From what I learned the only way to "overload" the function in JSDocs is a union type, and that would look pretty messy and require Do you want me to submit a PR with the other overloads I created and you commit the parse function signature? And we convert this to TypeScript ? It does seem to be a better fit. |
I just discovered that the newly-released TypeScript 5.0 includes an https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#overload-support-in-jsdoc |
That sound awesome! I'll read up on it. |
That just came out, I skimmed through it two days ago and didn't catch |
This seems to be working okay for me in testing locally, want me to go ahead and push it up? Or do you want to take a closer look at it? /**
* @template {(node: Element) => any} F
* @typedef {(node: Element) => any} MatcherFn
*/
/**
* @template {(node: Element) => any} F
* @typedef {Record<string, MatcherFn<F>>} MatcherObj
*/
/**
* @template {MatcherObj<F>} O
* @template {MatcherFn<any>} F
*
* @overload
* @param {string|Element} source Source content
* @param {O} matchers Object of matchers
* @return {{[K in keyof O]: ReturnType<O[K]>}} Matched values, shaped by object
*/
/**
* @template {MatcherFn<any>} F
*
* @overload
* @param {string|Element} source Source content
* @param {F} matcher Matcher function
* @return {ReturnType<F>} Matched value
*/
/**
* Given a markup string or DOM element, creates an object aligning with the
* shape of the matchers object, or the value returned by the matcher.
*
* @template {MatcherObj<F>} O
* @template {MatcherFn<any>} F
*
* @param {string|Element} source Source content
* @param {O|F} matchers Matcher function or object of matchers
*/
export function parse(source, matchers) {
// ...
} |
I just pushed something up. Sorry I can walk it back. Can I also do the comments like that rather than all spaced out like they do on Gutenberg? |
@aduth I was going to walk some of it back, but it was breaking everything else. Could you take a look at the current version, and push any updates. I'll stop working on it until I hear from you. I'm really happy with how this turned out. Thanks so much for point out |
Hey, no worries and no need to walk anything back. I had to step away for a bit anyways, so it worked out. And it looks like you've got most everything in place now. Glad that new feature worked well! |
Only issue I see with the new feature is that none of the comments came with the overloads, in the output |
And yes, I'd be fine to collapse the whitespace in the JSDoc if you want to do that. |
Hm, yeah, I see what you mean 🤔 |
@aduth I tried adding the description to all the overloads, but nothing worked. Other than that, I think it's ready for review. |
Yeah, I didn't have any luck either. Do you think it should be a blocker? I'm okay to ship it without the comments if you are. Seems like it might be a bug in TypeScript itself. Only other option I could conceive is to port to TypeScript. |
This is checked-in to source control include manual revisions documenting overloaded functions, due to a suspected upstream bug in TypeScript. See: microsoft/TypeScript#53350
@johnhooks I pushed up changes in 60a48ca to check-in the One other thing that comes to mind is that the matcher object form supports arbitrary nesting of objects. Would it be easy enough to change the Playground example: |
@aduth That issue filed on TypeScript looks great to me. That type makes sense to me though the type checker isn't happy with it. /**
* @typedef {(node: Element) => T} MatcherFn
* @template T
*/
/**
* @typedef {Record<string, MatcherObj<T> | MatcherFn<T>>} MatcherObj
* @template T
*/
/**
* @typedef {(MatcherFn<T>|MatcherObj<T>)} Matcher
* @template T
*/ Results in:
I have always had trouble understanding the nuance of circular references, sometimes they work fine. This works though... /**
* @typedef {(node: Element) => T} MatcherFn
* @template T
*/
/**
* @typedef {{[ x: string ]: MatcherObj<T> | MatcherFn<T>} } MatcherObj
* @template T
*/
/**
* @typedef {(MatcherFn<T>|MatcherObj<T>)} Matcher
* @template T
*/ |
But it creates a new type error in parse. |
I think I got it working in TypeScript with a combination of your suggestion of the object index signature, plus an update on the return signature of the object overload to be conditional based on the object value. I couldn't quite get it working in JSDoc, though I did make a bit of progress by making the Maybe we're back at reconsidering TypeScript 😅 |
add TypeScript
This is checked-in to source control include manual revisions documenting overloaded functions, due to a suspected upstream bug in TypeScript. See: microsoft/TypeScript#53350
@johnhooks Looks like we both had the same idea this afternoon, I had also gone down this path of porting in 489bcdf, but it looks like you beat me by a few minutes. 😄 |
Check it out, the only thing that I couldn't figure out was how to run the tests. |
The overloads have all the comments now, like they should. |
It looks like you know how to register babel for tests with ts extensions! Awesome. |
I'm going to pause on this. There are still some issues to resolve, but it seemed like I might have been stepping on your toes! I'll wait to hear from you. Also, it seemed like you were getting in to it, do you want to implement the same for rememo and memize, or would you like help? |
@johnhooks No toe-stepping at all! I had dug a little deeper than I expected out of curiosity, and should have communicated earlier. I'm not too worried from my point-of-view about having duplicated the work, since it was an interesting TypeScript challenge. If you want to go ahead and work through those remaining issues, please feel free. Maybe there are some useful bits from my commit that you can use (e.g. I noticed that the object return type I mentioned in my earlier comment needed a bit more work to resolve the return type of deeply nested functions). My availability may be a bit spottier again over the next days, but if you reach a good stopping point, let me know and I'll try to make some time to help publish the finished version. Similarly, I may not have the bandwidth to take a look at those other projects in the short term, so if you want to take a stab at it, I'd appreciate that. |
3312c04
to
b530fe2
Compare
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.
@aduth this PR is ready for a review. I'm very happy with the solutions we came up with. Thank you so much for your help and support.
.gitignore
Outdated
@@ -1,4 +1,4 @@ | |||
es/ | |||
/es/* |
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.
@aduth I think this is from when we were going to check in the es/index.d.ts
file, should it be reverted back to the original?
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.
Yeah, I think we could revert it to simplify the diff, but this appears to work just as well, so I'm also fine to keep as-is.
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.
This is all looking fantastic! Thanks for bearing with me through all the iterations. I think it turned out great in the end. I'll plan to get this merged and published either later today or at least by the end of the weekend.
.gitignore
Outdated
@@ -1,4 +1,4 @@ | |||
es/ | |||
/es/* |
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.
Yeah, I think we could revert it to simplify the diff, but this appears to work just as well, so I'm also fine to keep as-is.
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.
@aduth, it is ready for final review.
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.
Awesome! Thanks again for all your work with this. Excited to see it help with your work typing Gutenberg packages. I'll be merging and publishing shortly.
This is now published as |
Goal
Enhance JSDoc types to be more explicit, enable TypeScript checking of JavaScript files, and prepare for publishing first-party types.
Closes #17
Notes
Type output directory
The types are currently output to the
es
folder. I thought that was more appropriate than thedist
folder with theUMD
builds, though I can change it to whatever you think is best.JSDoc parameter descriptors
?
or=
TypeScript interprets
?
as a union withnull
and=
as a union withundefined
in all the instances I believe the correct union should beundefined
, that is why I change it.Using JSDoc over TS
Generics in JSDoc are awkward and I am not familiar with the syntax. To figure out the solution, I first converted
src/index.js
to a TypeScript file and worked in what I was most familiar with. I wasn't able to bring all the same types into the JSDoc version.