DEV Community

Cover image for TypeScript: Using any in Generic Constraints
Dan Fletcher
Dan Fletcher

Posted on

TypeScript: Using any in Generic Constraints

Why any is bad

They any type in TypeScript is usually considered unsafe 99.99% of the time. This is why any is so dangerous:

const str: any = 'I am a string'
const num: number = str
num // 'I am a string'
Enter fullscreen mode Exit fullscreen mode

Even though we're telling TS that num must be of type number, because the type of str is any it can easily be assigned to num even if the value is not a number.

Like I said, 99.99% of the time, any is bad. But there is one case in TypeScript where it's completely type safe to use any!

Generic constraints

When we are working with generics in TS we can constrain the generic using the extends keyword.

For example I might have a PetOwner type that has a list of pets, but I want it to be generic so that I can make the array contain only cats, or only dogs.

type PetOwner<T extends Array> = {
  pets: T
}
Enter fullscreen mode Exit fullscreen mode

This type will currently cause a type error because the Array type requires a type argument. So lets give it one:

type PetOwner<T extends Array<any> = {
  pets: T
}
Enter fullscreen mode Exit fullscreen mode

Now at first you may think that this is dangerous. We're using any! But lets look at what actually happens when we use this type:

const dogLover: PetOwner<Dog[]>
Enter fullscreen mode Exit fullscreen mode

What is the type of dogLover here? If you gessed {pets: Array<Dog>} you're correct!

This is because when any is used in a generic constraint, TypeScript discards it and replaces it with whatever the type argument was, assuming that it matches the constraint. Dog[] matches the constraint of Array<any> so T gets the type Dog[].

any is still dangerous if you use it as a type argument. If I instead used PetOwner<any[]> it would have all the same pitfalls as using any in any other context outside of a generic constraint.

A note on unknown

unknown behaves exactly the same way as any in this context, so it may be preferable to use unknown but it’s totally up to preference.

For myself, I think any reads better. It describes the intent of the type code more clearly. T must be an array, but it can be an array of anything. Using unknown doesn't convey that message as well in my opinion.

Latest comments (0)