skip to Main Content

I want to write a function that gets a parameter of type T | [string, T][] and checks if the parameter is of type T and not of type [string, T][].
example:

const example: null | [string, null][] = [['addr1', null], ['addr2', null] ] 
it's type is not null (null is T)

T is not class, it is usually string, number, string[]….

My first implementation was:

function isTypeT<T>(response: T | [string,T][], singleResType: new () => T): boolean {
  return response instanceof singleResType;
}

but it requires that the type T must have a constructor.
(typeof function will not help because :

typeof string[] == typeof [string, string[]][] == object

)

I also thought about this:

function isTypeT<T>(response: T | [string, T][], singleRes: T): boolean {
    if (Array.isArray(response) && Array.isArray(singleRes)) {
        return isTypeT(response[0], singleRes[0]);
    } 
     else if (typeof response !== typeof singleRes || Array.isArray(response) || Array.isArray(singleRes)) {
        return false;
    }
    return true;
}

but passing a sample object every time to check the function doesn’t seem like a good typescript implementation.

So, I would appreciate it if anyone could suggest another way to check the types.

2

Answers


  1. import { type } from 'arktype'
    
    // not gonna write the checks myself
    const stringAnyTupleArray = type([['string', 'any'], '[]']);
    
    const isStringAnyTupleArray = stringAnyTupleArray.allows;
    // const isStringAnyTupleArray: (data: unknown) => data is [string, any][]
    
    function isNot<T>(isT: (v: unknown) => v is T) {
      return function isNotT<V>(v: V): v is Exclude<V, T> {
        return !isT(v);
      }
    }
    
    const isNotStringAnyTupleArray = isNot(isStringAnyTupleArray);
    // const isNotStringAnyTupleArray: <V>(v: V) => v is Exclude<V, [string, any][]>
    
    function foo<T>(t: T | [string, T][]) {
      if (isNotStringAnyTupleArray(t)) {
        ;; t
        // ^?
      } else {
        ;; t // doesn't work
        // ^?
      }
      if (isStringAnyTupleArray(t)) {
        ;; t
        // ^?
      }
    }
    
    Login or Signup to reply.
  2. This is not possible in general. Consider

    type Infinite = [string, Infinite][]
    isTypeT<Infinite>([])
    

    where you cannot distinguish T (Infinite) from [string, T][] since they are the same. Sure, if T is not an array type, you can distinguish them, but you cannot do that for an arbitrary (parameterised) generic type.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search