I am using JSDoc in a JavaScript project which is checked using the TypeScript compiler.
In TypeScript, I can create a generic type like so:
type Optional<TType extends string> = { type: TType; optional?: boolean; } | { type: `${TType}?` };
type OptionalThing = Optional<'thing'>;
The resolved and flattened value of OptionalThing is now this:
type OptionalThing =
| { type: 'thing'; optional?: boolean; }
| { type: 'thing?'; }
This type creates a type union where one member type has the literal and const thing value for the type field and it has an additional optional boolean field and the other member type has literal and const thing? for the type field and doesn't have the optional field.
The ? suffix on type is a short-hand syntax for marking a thing as optional in the problem I am solving so specifying optional in addition needs to be forbidden otherwise it would be possible to represent an invalid value: { type: 'thing?', optional: false }.
In other words:
/* These are allowed - they conform to the type */
const optionalThing1: OptionalThing = { type: 'thing?' };
const optionalThing2: OptionalThing = { type: 'thing', optional: true };
const optionalThing3: OptionalThing = { type: 'thing', optional: false };
// This is disallowed, `optional` cannot be specified while `type` has `?` suffix
const optionalThing4: OptionalThing = { type: 'thing?', optional: false };
// This is disallowed, `type` must be either `thing` or `thing?` const string
const optionalThing5: OptionalThing = { type: 'not literally "thing"' };
Playground (configured to TypeScript)
I am having trouble translating this to JSDoc that would have the same behavior in TypeScript. I tried this:
/** @typedef {{ type: T; optional?: boolean; } | { type: `${T}?`; }} Type<T> */
/** @template {string} T */
/** @typedef {Type<'thing'>} ThingType */
// Error: Type 'Type' is not generic.
Playground (configured to JavaScript)
How can I made a generic typedef in JSDoc such that the above TypeScript logic works the same way when TypeScript checks the JavaScript and JSDoc version?
d.tsfiles and just use them in JS/** @type {import('types.d.ts')} */?d.tsIf you export it should work withimport('./types').Generic<{ o: string }>