Type Parameters as Constraints

TypesScript 1.8 introduced the concept of type parameters as constraints, also known as F-Bounded Polymorphism.

But what does type parameters as constraints really mean? To answer that question we first need to understand what a type parameter is.

What is a Type Parameter?

A Type Parameter is a placeholder for a type. They're used with generics and allow you to defer the decision of choosing a type. The actual type is provided when the generic type is used.

Consider the following custom type that uses a type parameter:

type myType<T> = T;

Here we've defined a new type called myType that uses a type parameter called T. When we use this type we will define what the type parameter T represents.

let count: myType<number>;

count = 1; // This is OK.

count = ''; // Error, number expected

In the above code we create a new count variable of type myType<number>. Comparing the usage of myType to it's definition, we can see that we've specified that the generic type T is number. This means the type of count is number, because that's exactly what our myType defined:

type myType<T> = T;

When we passed number we basically wrote:

type myType<number> = number

Which basically boils down to:

type myType = number

which is the same as using the number type directly.

Type Parameters as Constraints

Now we know what a type parameter is we can use this knowledge to help us understand what type parameters as constraints actually means.

From my understanding, this simply means that the type parameter can be used a type parameter constraint, that is, it can be used to constrain the type passed in as a parameter to the same type as the type parameter. This is easier to understand with a code snippet:

type funcType<T> = (a: T) => T;

The above snippet defines a new function type called funcType. This type utilises the type parameters as constraints feature - it constrains the type of the argument a to the type of T. If T is a number, then argument a must be a number too.

const myFunc: funcType<number> = a => a; 

myFunc(1) // This is OK.

myFunc(true) // Error, expected number.

Conclusion

The term type parameters as constraints wasn't intuitive to me. I wrote this article to help me understand what this term actually means. As we discovered, type parameters as constraints basically means we can constrain the type of a function argument to the same type as the provided type parameter. As long as you understand that a type parameter is used to defer the decision of a type for generics, the description previously provided should make sense.