-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Generic types from JSDoc aren't really generic #26883
Comments
Hello. My goal is to use JavaScript along with So my workflow looks a little like this. This is what my declaration file looks like. // test.d.ts
export declare function addToCollection<T>( collection:T[], val:T):T
export as namespace test; Then I implement it in a JS file like this. // test.js
/**
* @type { test.addToCollection }
**/
export function addToCollection( collection, val ) {
return collection.push( val )
} The problem here is that Generics are ignored. If the Any suggestions on this, or am I using it wrong? |
@michaelolof You are using it wrong. For your example, you should change the JSDoc for /**
* @template T
* @param {T[]} collection
* @param {T} val
* @returns {T}
*/ and you should no longer need |
Thank you for replying. I kind of understand where you're coming from and I can probably tell this pattern is definitely not conventional. My issue with the JSDoc approach, is that it can get really verbose. Consider a typed pipe function like this in a typescript file. export function pipe<T1, R>(
fn1: (arg1: T1) => R,
...fns: Array<(a: R) => R>
): (arg1: T1) => R;
export function pipe<T1, T2, R>(
fn1: (arg1: T1, arg2: T2) => R,
...fns: Array<(a: R) => R>
): (arg1: T1, arg2: T2) => R;
export function pipe<T1, T2, T3, R>(
fn1: (arg1: T1, arg2: T2, arg3: T3) => R,
...fns: Array<(a: R) => R>
): (arg1: T1, arg2: T2, arg3: T3) => R;
export function pipe<T1, T2, T3, T4, R>(
fn1: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R,
...fns: Array<(a: R) => R>
): (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R;
export function pipe<R>(
fn1: (...args: any[]) => R,
...fns: Array<(a: R) => R>
): (a: R) => R {
return fns.reduce((prevFn, nextFn) => value => nextFn(prevFn(value)), fn1);
} I shudder to think of how this would be implemented with JSDoc. For me i believe the biggest benefit of this Also you have to consider this is an approach that works already in TypeScript. It just breaks when using generics. I hope you do consider it. Great job with all the work @typescript. |
/** @typedef {{
* <T1, R>(
* fn1: (arg1: T1) => R,
* ...fns: Array<(a: R) => R>
* ): (arg1: T1) => R;
* <T1, T2, R>(
* fn1: (arg1: T1, arg2: T2) => R,
* ...fns: Array<(a: R) => R>
* ): (arg1: T1, arg2: T2) => R;
* <T1, T2, T3, R>(
* fn1: (arg1: T1, arg2: T2, arg3: T3) => R,
* ...fns: Array<(a: R) => R>
* ): (arg1: T1, arg2: T2, arg3: T3) => R;
* <T1, T2, T3, T4, R>(
* fn1: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R,
* ...fns: Array<(a: R) => R>
* ): (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => R;
* }} PipeFunction
*/
/** @type {PipeFunction} */
const pipe = (fn1, ...fns) => {
return fns.reduce((prevFn, nextFn) => value => nextFn(prevFn(value)), fn1);
}; |
Yes I've tried this. It's verbose but still suffers from the same problem as the
For a simple one line implementation like the as above this might not be a problem, but implementing a generic function with about 7+ lines of code and you start to see how this might be a problem. |
This is where the internet led me regarding how to call functions with specific generic args using JSDoc. How would we call, for example, the above @sandersn If I understand correctly, that's what you're saying we can't currently do, right? It would be really great to have all the features of TS in JSDoc, because then it means we could use generic JSDoc tooling (not just the too-inflexible TSDoc) without duplicating type information in both source and comments. |
@trusktr You are correct, there is no way to call functions with type arguments. We view it as a code smell in TS, since it's basically a more-widely-propagated, but non-obvious, cast. I recommend just using a cast in JS, and later rewriting the function so that its type arguments can be inferred [1]. We do not have general plans to replicate all of TS's features in JS, since we think that most people who want TS' features will eventually switch to TS anyway. The main user we care about for JSDoc is the one who never thinks about TS, or types for that matter. [1] This may mean getting rid of all type parameters and forcing callers to cast. |
I have a much simpler scenario that you may fall between something as complex as the previous example and very basic types. I think many people may be interested into being able to use generics like this on JSDoc:
The problem is that any function that I wrap gets the generic type as any: I can "force" the type by doing this:
Is there any shorter way? I just don't want to have the return type on every wrapped function |
Is there any work around for creating an object signature with a generic value? |
I'm looking for using generics in types defined in |
That is already possible. You can import them reference types from jsdoc comments |
It kindof works. I was not able to get generics to work correctly from jsdocs though. It would be great if there was a guide on using generics from jsdocs. |
I get that you have to prioritise, but it's sad to hear. I strongly prefer to write Javascript instead of Typescript just because it removes a building step. But I still "think about types". For me it's about setting up simpler projects with less moving parts. |
There is a growing culture of library developers who write the implementation javascript & hand-write .d.ts. I've seen a few prominent developers who write js for their library code & ts for their app code. Writing in js removes the build step, which helps with tooling compatibility (e.g. vite) & build performance. With the new tooling projects coming out, it helps to keep libraries simple.
https://docs.joshuatz.com/cheatsheets/js/jsdoc has been helpful |
Expected behavior:
n: number
Actual behavior:
n: any
in 3.0;n: V
in 3.1-dev.Types resolved from functions are never properly generic, even that function has
@template
-specified type parameters; they're only special-cased in a few places to produce a specific instantiation of a type. They should use the normal generic type machinery that Typescript does.The text was updated successfully, but these errors were encountered: