Search code examples
javascripttypescriptgoogle-closure-compiler

Refining generic type in typescript


In google closure compiler, you can refine a generic by doing typeof or instanceof. For example, here I take a generic and treat it like an object:

/**
 * @param {T} obj
 * @return {T}
 * @template T
 */
function cloneIfObject(obj) {
  if (typeof obj === 'object') {
    return objectClone(obj);
  }
  return obj;
}

/**
 * Stub function that only accepts object type
 *
 * @param {!Object} obj
 * @return {!Object}
 */
function objectClone(obj) {
  return obj; //Pretend to clone
}

I tried implementing this in typescript, but I'm unable to treat it like an object.

function cloneIfObject<T>(obj: T) {
    if (typeof obj === 'object') {
        return { ...obj }; //Error: Spread types may only be created from object types.
    }

    if (obj instanceof Object) {
        return { ...obj }; //Error: Spread types may only be created from object types.
    }

    return obj;
}

Solution

  • You cannot use typeof for what you are trying to do:

    These typeof type guards are recognized in two different forms: typeof v === "typename" and typeof v !== "typename", where "typename" must be "number", "string", "boolean", or "symbol". While TypeScript won’t stop you from comparing to other strings, the language won’t recognize those expressions as type guards.

    The second one will be a valid use, as soon as they fix this bug (there is already a PR).