Home  >  Q&A  >  body text

Why does TS complain when using @type instead of @param and @return when writing a generic function?

Why TS is complaining about this:

/**
 * @template X
 * @type {function(X): X}
 */
const identity1 = (x) => x;

/**
 * @template X
 * @type {function(X): X}
 */
const identity2 = (x) => identity1(x);

TypeScript Error Message:

Type 'X' is not assignable to type 'X'. Two different types with this name exist, but they are unrelated.
  'X' could be instantiated with an arbitrary type which could be unrelated to 'X'.ts(2719)
graph.mjs(4, 14): This type parameter might need an `extends X` constraint.
const identity1: (arg0: X) => X
@template X
@type — {function(X): X}

However, when changing the @type using @param and @return it works fine:

/**
 * @template X
 * @param {X} x
 * @returns {X}
 */
const identity1 = (x) => x;

/**
 * @template X
 * @type {function(X): X}
 */
const identity2 = (x) => identity1(x);

I do not understand why. The documentation makes no mention of how these two signatures interact differently with generic types.

P粉464082061P粉464082061180 days ago337

reply all(1)I'll reply

  • P粉448130258

    P粉4481302582024-04-04 10:26:28

    Use the @type tag to refer to the type range limited to curly braces. That is, @type {function(X): X} does not refer to the generic type because we referenced X outside the scope. At least that's my interpretation. Regardless, extracting the provided type from @type is not supported.

    However, you can use @typedef to override functions:

    /**  
    * @template X  
    * @typedef {X extends number ? [1, 2, 3][X] : never} Successor  
    */ 
    
    /**  
    * @template X  
    * @typedef {X} Identity  
    */ 
    
    /**
    * @template X  
    * @typedef {Identity>} Identity2  
    */
    
    /** @type {Successor>} */ 
    const x = 2;  
    
    

    reply
    0
  • Cancelreply