Type Challenges: Implement the IsAny<T> Utility Type
99% of TypeScript Developers Have Used the Any Type. But Only 20% of Developers Know How To Detect Any Type.
Welcome to the Mastering TypeScript series, there are dozens of articles in this series. To help readers better consolidate their knowledge of TypeScript, I have selected a few dozen challenges from the type-challenges repository on Github to complete the type challenge with you.
- Type Challenges: Implement the Built-In Pick
Utility Type - Type Challenges: Implement the Built-In Omit
Utility Type - Type Challenges: Implement the RequiredByKeys
Utility Type - Type Challenges: Implement the PartialByKeys
Utility Type - Type Challenges: Implement the PickByType
Utility Type
Challenge
Sometimes it’s useful to detect if you have a value with
any
type. This is especially helpful while working with third-party TypeScript modules, which can exportany
values in the module API. It's also good to know aboutany
when you're suppressing implicitAny checks.
So, let’s write a utility type
IsAny<T>
, which takes input typeT
. IfT
isany
, returntrue
, otherwise, returnfalse
.
For example:
type A = IsAny<any> // expected to be true
type B = IsAny<undefined> // expected to be false
type C = IsAny<unknown> // expected to be false
type D = IsAny<never> // expected to be false
type E = IsAny<string> // expected to be false
Solution
Our type challenge is to implement the IsAny<T>
generic, before we analyze how to implement this generic type, let’s briefly introduce the any
type.
Any Type
In TypeScript, any
type is called the top type. The so-called top type can be understood as a generic parent type, that is, a type that can contain all values.
In fact, any type is essentially an escape hatch for the type system, and TypeScript allows us to perform any operation on the value of any type without performing any kind of prior checking.
What’s the problem with this? Let’s take an example:
For the above TypeScript code, no errors will be prompted at compile time, but runtime errors will be thrown at runtime. As developers, any
type gives us a lot of freedom, but it also brings some pitfalls. In order to solve the security risks of any
type, the TypeScript team introduced the unknown
type in 3.0, which you can understand as a type-safe any
type.
I won’t go into the difference between any
type and unknown
type, but you can read the following article if you are interested.
Finally, let’s look at the complete code:
type IsAny<T> = 0 extends T & 1 ? true : false
type A = IsAny<any> // true
type B = IsAny<undefined> // false
type C = IsAny<unknown> // false
type D = IsAny<never> // false
type E = IsAny<string> // false
In TypeScript, the &
operator is provided for us to implement the intersection operation on multiple types, and the resulting new type is called the intersection type.
Let’s briefly introduce the &
operator, which satisfies the following rules:
- Identity:
A & A
is equivalent toA
. - Commutativity:
A & B
is equivalent toB & A
(except for call and construct signatures as noted below). - Associativity:
(A & B) & C
is equivalent toA & (B & C)
. - Supertype collapsing:
A & B
is equivalent toA
ifB
is a supertype ofA
.
In the above code, any
type and never
type are special. Except for the never
type, other type intersecting with any
type will result in any
type.
After understanding the characteristics of the any
type, let’s take a look at the output of T & 1
when the T
type parameter is of a different type:
type A1 = any & 1 // any
type B1 = undefined & 1 // never
type C1 = unknown & 1 // 1
type D1 = never & 1 // never
type E1 = string & 1 // never
After mastering the above content, the rest is the related content of TypeScript conditional types, which will not be introduced here. I recommend you to read this article:
If there is anything unclear, please leave me a message. You also can follow me on Medium or Twitter to read more about TypeScript and JavaScript!