I have the following interfaces and types:
type TransformOptions = 'auto' | 'binary' | 'json';
interface Get {
/**
* How long to keep the value in cache
*/
maxAge?: number
/**
* Whether to decrypt the param or not
*/
decrypt?: boolean
/**
* Whether to transform the param or not
*/
transform?: TransformOptions
}
interface GetTransformJson extends Get {
/**
* Whether to transform the param or not (json)
*/
transform?: 'json'
}
interface GetTransformNo extends Get {
transform?: never
}
type GetOptions = GetTransformNo | GetTransformJson | undefined;
type RetType<O = undefined> =
undefined extends O ? string :
O extends GetTransformNo ? string :
O extends GetTransformJson ? Record<string, any> :
never;
Which I use in this (simplified) function:
declare function apiCall(name: string): Promise<string>;
const getParameters = async <O extends GetOptions | undefined>(name: string, options?: O): Promise<RetType<O> | undefined> => {
const value = await apiCall(name);
if (options?.transform === 'json') {
const parsed = JSON.parse(value);
return parsed as RetType<O>;
} else {
return value as RetType<O>;
}
}
When I use this function (see example below), I would like to have annotations/comments that document each one of the fields of the options interface like below:
but instead, since it’s a generic (I think), I get nothing:

Since I’m building a library, I would like to have comments/documentation for all the properties in the options object, but using the current generics setup I am not able to.
EDIT 1
Following this answer, I have updated the signature of the function to this:
const getParameters = async <O extends GetOptions | undefined = undefined>(
name: string,
options?: O & GetOptions
): Promise<RetType<O> | undefined> => {
Now the docs/comment on the transform method work and seem to get picked up from the GetTransformJson interface (see (json) at the end of the comment:

However if I try to do the same but with a different attribute that comes from the base interface (i.e. decrypt) I don’t get the docs/comments:
>Solution :
In this case, it should be safe to intersect O with Get to "carry over" doc comments:
const getParameters = async <O extends GetOptions | undefined = undefined>(
name: string,
options?: O & Get
): Promise<RetType<O> | undefined> => {
Also, you should probably default to undefined for O.
Unfortunately, this won’t allow you to use the doc comment specific to GetTransformJson…
After some experimentation, I found this:
const getParameters = async <O extends GetOptions | undefined = undefined>(
name: string,
options?: O & (O extends GetTransformNo ? GetTransformNo : O extends GetTransformJson ? GetTransformJson : Get)
): Promise<RetType<O> | undefined> => {
which does preserve doc comments specific to GetTransformJson and GetTransformNo, but at the cost of readability and maintenance.

