I want to make this function that receives a parameter and return its class if object
, the parameter itself if function
or the legacy object constructor if anything else.
In JavaScript the example below covers the functionality for most cases. But the JSDoc doesn’t follow…
export const ParseType = ( Subject ) =>
{
if ( ( typeof Subject == 'function' ) && ( typeof Subject.prototype == 'object' ) )
{
return Subject;
}
return Object(Subject).constructor;
}
function MyCustomType ()
{
}
// JSDoc signature: () => void
const MyCustomInstance = new MyCustomType;
// JSDoc signature: any
// Expecting JSDoc signature: MyCustomType
const MyRetrievedCustomType = ParseType(MyCustomInstance);
// JSDoc signature: any
// Expecting JSDoc signature: typeof MyCustomType
To fix this issue, I can do something like this:
/**
* @template [Type = InstanceType < typeof Object >]
* @param { Type } [Subject = Type]
*/
export const ParseType = ( Subject ) =>
{
let Inferred;
if ( ( typeof Subject == 'function' ) && ( typeof Subject.prototype == 'object' ) )
{
Inferred =
(
/**
* @type { Type extends Function & { prototype: {} } ? Type : never }
*/
( Subject )
);
}
else
{
const Instance =
(
/**
* @type { Subject & {} }
*/
( Object(Subject) )
);
Inferred =
(
/**
* @type { Type extends Function & { prototype: {} }
* ? never
* : Instance extends { constructor: infer Constructor }
* ? Constructor
* : never
* }
*/
( Instance.constructor )
);
}
return Inferred;
}
/**
* @constructor
*/
function MyCustomType ()
{
}
// JSDoc signature: typeof MyCustomType
const MyCustomInstance = new MyCustomType;
// JSDoc signature: MyCustomType
const MyRetrievedCustomType = ParseType(MyCustomInstance);
// JSDoc signature: Function
// Expected JSDoc signature: typeof MyCustomType
// JavaScript actual value: [Function MyCustomType]
const MyRegrievedStringType = ParseType('MyString');
// JSDoc signature: Function
// Expected JSDoc signature: StringConstructor
// JavaScript actual value: [Function String]
I can’t extract the constructor from Instance
correctly because JSDoc infers the constructor at ObjectConstructor.constructor
which is Function
. Oddly enough, when I’m extracting the constructor
from Instance
, in the casting JSDoc type tag I can test Instance
against any class and evaluate as the “hard coded” class…
/**
* @type { Instance extends MyCustomType ? typeof MyCustomType : never }
*/
Or even chaining like this…
/**
* @type { Instance extends String ? typeof String : Instance extends BigInt ? typeof BigInt : never : never }
*/
But I can’t just keep increasing this chain and hard coding all the classes that could possibly be used in any project that will use this function…