X Tutup
The Wayback Machine - https://web.archive.org/web/20201211214418/https://github.com/microsoft/TypeScript/issues/27387
Skip to content
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

Allow to explicitly pass parameter types via JSDoc #27387

Open
ifeltsweet opened this issue Sep 27, 2018 · 5 comments
Open

Allow to explicitly pass parameter types via JSDoc #27387

ifeltsweet opened this issue Sep 27, 2018 · 5 comments

Comments

@ifeltsweet
Copy link

@ifeltsweet ifeltsweet commented Sep 27, 2018

Search Terms

jsdoc generics type parameters constraints

Suggestion

It seems like it is not possible via JSDoc to explicitly tell compiler which type parameters to pass to a generic function.

Use Cases

In TypeScript it is possible to explicitly pass type parameters such as mongoose.model<Model, Schema>('modelName', Schema) while I could not find a way to do same with JSDoc.

Examples

mongoose.model has two signatures, first one with one type parameter and the other with two. To make use of the second signature we must pass types explicitly.

export function model<T extends Document>(
  name: string,
  schema?: Schema,
  collection?: string,
  skipInit?: boolean
): Model<T>;

export function model<T extends Document, U extends Model<T>>(
  name: string,
  schema?: Schema,
  collection?: string,
  skipInit?: boolean
): U;
//  Choose second signature in typescript.
const model = mongoose.model<Model, Schema>('modelName', Schema);

// With JSDoc, compiler always chooses first signature and we receive a type mismatch error.
/** @type {Schema & mongoose.Model<Model>} */
const model = mongoose.model('modelName', Schema);

// But something like this would be great.
const model = mongoose.model/**<Model, Schema>*/('modelName', Schema);

My apologies if this is already possible, but I've spend almost a week battling this.

Related: microsoft/TypeScript-Node-Starter#101

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)
@Stuk
Copy link

@Stuk Stuk commented Mar 12, 2019

I would also like to see something like this. Currently it's really hard to use functions with generic types from JS.

@ekulabuhov
Copy link

@ekulabuhov ekulabuhov commented Nov 7, 2019

Another use case with React Hooks:

// useState<string> is derived correctly
const [aString, setAString] = useState("default value");

Removing default value there is no way to pass type info:

// useState<any>
const [aString, setAString] = useState();
@pm0u
Copy link

@pm0u pm0u commented May 1, 2020

Anything on this? Also stuck on the useState example as shared above:

// Doesn't set type properly
const [error, setError] = /** @type {React.useState<?string>} */ useState(null);
// Nor does this
/** @type {[?string, React.Dispatch<React.SetStateAction<?string>>]} */
const [error, setError] = /** @type {React.useState<?string>} */ useState(null);


// we have an error we want to set now.
setError('Error!') // Shows a type error

Edit: Ok this might be a hack, but in the case of the useState example it works:

const [error, setError] = useState(/** @type {?string} */ (null));

implied types for error are string | null and setError is React.Dispatch<React.SetStateAction<?string>>

i think what's happening "under the hood" is we are forcing the "type" that useState is being passed.

@robertknight
Copy link

@robertknight robertknight commented Jul 16, 2020

For functions that take an argument of the generic type, casting the argument itself is reasonably practical. We've settled on these patterns with useState and useRef in React for example:

const [thing, setThing] = useState(/** @type {SomeType|null} */ (null));
const widgetRef = useRef(/** @type {HTMLElement|null} */(null));

In cases where there is no argument for everything else to be inferred from, it gets much more verbose unfortunately. What would be helpful is being able to do something like:

const aSet = /** @type {?<string>} */(new Set());

Where the ? is inferred as Set. In this example it only saves a few characters, but it could be a lot more if the generic type name is lengthy and/or has to be imported from somewhere.

@k-yle
Copy link
Contributor

@k-yle k-yle commented Jul 16, 2020

Where the ? is inferred as Set. In this example it only saves a few characters, but it could be a lot more if the generic type name is lengthy and/or has to be imported from somewhere.

Something like that would be awesome, it would majorly simplify the code required for React.forwardRef and React.memo:

- const Component = /** @type {React.ForwardRefExoticComponent<React.RefAttributes<Props>>} */ (React.forwardRef(() => { ... }))
+ const Component = /** @type {?<Props>} */ (React.forwardRef(() => { ... }))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants
You can’t perform that action at this time.
X Tutup