How To Use TypeScript’s Built-In ConstructorParameters Type
A dive into TypeScript’s ability to infer constructor parameters, for all of your class-based object-oriented programming needs. Read this one if you need a refresher on JavaScript classes 😉
TypeScript’s Type for Typing Constructor Parameters
When it comes to TypeScript, the language isn’t just about adding static types to modern JavaScript. It’s also about augmenting your JavaScript with a healthy, rich diet of built-in utility types to make your coding life easier. Among these utilities is the built-in ConstructorParameters type.
Ever been in a situation where you wanted to know the exact arguments required by a constructor? I honestly never had before researching this article! But if you’re coming from another programming language like Java or PHP, writing classes will be natural for you, and they’re valid TypeScript! ConstructorParameters is what you need if you’re dealing with constructors.
Quick Review: Constructors and Classes in JS/TS
First, let’s review the key concepts that we’re working with when we discuss JavaScript classes, and specifically creating them with the class keyword.
Classes
Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on prototypes but also have some syntax and semantics that are unique to classes.
For more examples and explanations, see the Using classes guide. — MDN Docs
Classes provide an object specification and are used to instantiate new objects that follow that specification. Typing that specification is smart!
class
The
classdeclaration creates a binding of a new class to a given name.
You can also define classes using the
class expression.
— MDN Docs
We define classes using the straightforward class name {} syntax, though you can also assign classes to const / let variables with
constructor
The
constructormethod is a special method of a class for creating and initializing an object instance of that class.
Note: This page introduces the
constructorsyntax. For theconstructorproperty present on all objects, seeObject.prototype.constructor.
— MDN Docs
Finally, when we write our constructors, we typically use public class field names, though sometimes we may use private class fields instead.
Private class features
Class fields are public by default, but private class members can be created by using a hash
#prefix. The privacy encapsulation of these class features is enforced by JavaScript itself.
— MDN Docs
In our examples, we’re not going to use the hash # prefix to specify private classes. Instead, we’ll stick to the public keyword in our constructors.
Public class fields
Public fields are writable, enumerable, and configurable properties. As such, unlike their private counterparts, they participate in prototype inheritance. — MDN Docs
When you don’t work with this stuff every day, it can be a little intimidating! But now you’re all caught up, so let’s talk constructor params.
Basic Usage of ConstructorParameters
Let’s take a fun TypeScript code example. Imagine you’re building a simulation with mapaches, and you have a class that defines a mapache:
/** Mapache mapache. Hiss! 🦝 */
class Mapache {
constructor(public name: string, public age: number) {}
}To know the types of the arguments required by the Mapache constructor, TypeScript’s built-in ConstructorParameters will come in handy:
/** Wait, how do I build an object of Mapache type again? */
type MapacheConstructorArgs = ConstructorParameters<typeof Mapache>Now, MapacheConstructorArgs is a tuple [string, number]. If you need a refresher on the concept of a tuple type, read my last article in this series.
Advancing Constructor Parameters Conditionally
Given that I’m writing for advanced developers who are able to understand this kind of code, let’s spice things up! 🌶️ Suppose we have another class:
/** Medium autodetects this code as PHP. SuperMapache! */
class SuperMapache extends Mapache {
constructor(name: string, age: number, public superPower: string) {
super(name, age)
}
}If we want a utility type to get the constructor arguments but exclude just the superPower parameter for some reason, we can use conditional types:
/** We want to exclude the `superPower` from the type. */
type ExcludeSuperPower<T> = T extends [infer Name, infer Age, ...infer Rest]
? [Name, Age]
: T
/** The result is going to be a tuple of `[string, number]`. */
type SuperMapacheConstructorArgs = ExcludeSuperPower<ConstructorParameters<typeof SuperMapache>>I know how intimidating that looks, but we’ll break it down, piece by piece. The first thing to understand is how TypeScript’s infer keyword works.
Here, we used the
inferkeyword to declaratively introduce a new generic type variable namedIteminstead of specifying how to retrieve the element type ofTypewithin the true branch. This frees us from having to think about how to dig through and probing apart the structure of the types we’re interested in.
— TS Docs
Instead of Item, we infer new generic types Name, Age, and the ... rest parameter, given as the generic type Rest. Pretty cool, right?
From there, we call our new ExcludeSuperPower type with a nested type: ExcludeSuperPower<ConstructorParameters<typeof SuperMapache>>.
The result is SuperMapacheConstructorArgs becomes [string, number], despite the original SuperMapache constructor requiring three arguments!
You can try this yourself in the TypeScript Playground. And if you’re finding the Playground code helpful, let me know in responses or by highlighting!
Conclusion: TypeScript’s Constructor Params Type
ConstructorParameters is a testament to knowing the difference between constructor, super, public, #private, class, generic <T>, and extends. And if you — dear reader — know all of the above, you are truly impressive!
We all want to use professional tools that make our lives as developers easier. With the ConstructorParameters type, hopefully you become a faster developer, more easily able to reuse types and ensure code quality
Actually, thinking about the constructors parameters and their types makes me see how classes could be used so that safety becomes a breeze. While it’s been a while since PHP was my favorite language, object-oriented programming concepts remain a foundational part of computer science.
Next time you see a mapache on the street, the beach, or the bus🦝, remember the flexibility and utility TypeScript offers. It might not give your mapache superpowers, but it certainly gives your codebase some!






