How To Strongly Type process.env
Learn how to strongly type process.env in TypeScript by either augmenting global type or validating it at runtime with t3-env.
Just like my previous article on Exclude, I’ve put together a bunch of different use cases for one of TypeScript's most useful helpers - Extract
.
Given a discriminated union, like Event
below, you often need to be able to access a single member of the union.
This can feel like an obscure problem, until you realize that Extract
is the perfect tool for the job.
Here, we're extracting the ClickEvent
type from the Event
:
ts
typeEvent =| {type : "click";x : number;y : number;}| {type : "focus";}| {type : "blur";};typeClickEvent =Extract <Event , {type : "click" }>;
We pass Event
as the first argument to Extract
, and then we pass the shape of the member we want to extract as the second argument.
Crucially, we don't need to pass the entire member to Extract
, just the shape we want to match. Beautiful.
Sometimes, we want to extract a specific member of a discriminated union based on its shape, rather than its discriminator.
Let's go back to our Event
type we declared earlier:
ts
typeEvent =| {type : "mousedown";x : number;y : number;}| {type : "mouseup";x : number;y : number;}| {type : "blur";};
Instead of extracting a member based on its discriminator, let's say we want to extract a member that has an x
property of type number
.
We can provide { x: number }
as the shape to match:
ts
typeClickEvent =Extract <Event , {x : number }>;
The result is the ClickEvent
type, which is the member of the Event
union that has an x
property of type number
. In this case, since both the mousedown
and mouseup
members have an x
property, the ClickEvent
type will be a union of these two members.
Let's consider a union type that includes a mix of strings, booleans, and numbers:
ts
typePossibleValues =| "admin"| "user"| "guest"| true| false| 1| 2| 3;
To extract all the string members from this union, we can use Extract<PossibleValues, string>
:
ts
typeStrings =Extract <PossibleValues , string>;
The result will be the Strings
type, which is a union of all the string members ("admin", "user", and "guest") in the PossibleValues
union.
Let's say we have a union type that includes a mix of strings, numbers, booleans, and functions:
ts
typePossibleValues =| string| number| boolean| (() => void);
To extract all the function members from this union, we can use Extract<PossibleValues, (...args: any[]) => any>
:
ts
typeFunctions =Extract <PossibleValues ,(...args : any[]) => any>;
(...args: any[]) => any
effectively matches any function type - so we can use it to extract all the function members from the union.
In this case, the Functions
type will only contain the () => void
function type.
There are times when we want to exclude certain types from a union. We may have a union type that includes null
and undefined
, but we want to create a new type that excludes those values.
ts
typePossibleValues =| string| number| boolean| null| undefined;
To exclude null
and undefined
from PossibleValues
, we can use Extract<PossibleValues, {}>
.
ts
typeNotNull =Extract <PossibleValues , {}>;
We can use {}
as the second argument to Extract
to match all types EXCEPT for null
and undefined
. You can learn more in this article on the empty object type.
In the following example, we have two union types: EnglishSpeakingCountries
and CountriesInWesternHemisphere
:
ts
typeEnglishSpeakingCountries = "UK" | "USA" | "Canada";typeCountriesInWesternHemisphere =| "USA"| "Canada"| "Mexico";
To find the common countries between these two unions, we can use the Extract
utility type like this:
ts
typeCommonCountries =Extract <EnglishSpeakingCountries ,CountriesInWesternHemisphere >;
The resulting CommonCountries
type will contain only the members that are present in both unions. In this case, the common country is "USA" as it exists in both unions.
Share this article with your friends
Learn how to strongly type process.env in TypeScript by either augmenting global type or validating it at runtime with t3-env.
Discover when it's appropriate to use TypeScript's any
type despite its risks. Learn about legitimate cases where any
is necessary.
Learn why TypeScript's types don't exist at runtime. Discover how TypeScript compiles down to JavaScript and how it differs from other strongly-typed languages.
Improve React TypeScript performance by replacing type & with interface extends. Boost IDE and tsc speed significantly.
In this book teaser, we discuss deriving vs decoupling your types: when building relationships between your types or segregating them makes sense.
Learn how TypeScript's new utility type, NoInfer, can improve inference behavior by controlling where types are inferred in generic functions.