Reputation: 11
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.
Upvotes: 1
Views: 217
Reputation: 665145
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.
Upvotes: 2
Reputation: 10899
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
// ^?
}
}
Upvotes: 0