jsdoc generics type parameters constraints
It seems like it is not possible via JSDoc to explicitly tell compiler which type parameters to pass to a generic function.
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.
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: https://github.com/Microsoft/TypeScript-Node-Starter/issues/101
My suggestion meets these guidelines:
I would also like to see something like this. Currently it's really hard to use functions with generic types from JS.
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();
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.
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.
Where the
?is inferred asSet. 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:
```diff
- const Component = /* @type {React.ForwardRefExoticComponent
+ const Component = /
Most helpful comment
Another use case with React Hooks:
Removing default value there is no way to pass type info: