Typescript Icon Get 42% off the TypeScript Bundle!

See the bundle then add to cart and your discount is applied.

0 days
00 hours
00 mins
00 secs
Typescript

Using 'Pick' in TypeScript to simplify Types and Interfaces

In this post you’ll learn how to use Pick in TypeScript to help clean up your codebase and make your type management far easier and cleaner!

What is Pick? Pick is what’s known as a Mapped Type, and I’ve covered other Mapped Types in my TypeScript Masterclass course.

Here’s the syntax for Pick:

Pick<Type, Keys>

We pass in an existing Type and then declare the Keys we wish to “pick” from the Type. Make sense? The Keys have to exist on the Type for you to be able to “pick” them, otherwise you’ll see a TypeScript error.

🛹 The opposite behaviour would be to use TypeScript’s Omit type instead.

Mapped Types allow us to dynamically construct new types from existing ones, creating a new type with new meaning. It allows us to create new types on the fly, without having to declare new types or interfaces.

For example, here is a common authentication service I’ve been working on lately, written in Angular and Firebase:

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor() {}

  async create({ name, email, password }: any) {...}

  async login({ email, password }: any) {...}

  async resetPassword({ email }: any) {...}
}

You’ll note that we are essentially using the same properties to “create”, “login” and “reset” a password. We use a mixture of name, email, password.

How could we type this? 🤔

Using the type keyword we could separately construct each property we expect and the using an Intersection Type to combine the types into new ones:

type Name = { name: string };
type Email = { email: string };
type Password = { password: string };

type CreateUser = Name & Email & Password; // { name: string, email: string, password: string }
type LoginUser = Email & Password; // { email: string, password: string }
type ResetPassword = Email; // { email: string }

We could then do this to add the types in the correct places:

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor() {}

  async create({ name, email, password }: CreateUser) {...}

  async login({ email, password }: LoginUser) {...}

  async resetPassword({ email }: ResetPassword) {...}
}

This is okay for such simple usage, but you can imagine expanding your codebase with more complex features and suddenly things begin spiralling out of control into a type world of pain.

This is where Pick comes into play. I aim for minimal code. No code is good code!

As we’ve looked at the syntax already, Pick accepts an existing Type and then the properties (Keys) that you’d like to “pick” from it.

First, let’s create a Credentials type via an interface, which will replace our stack of type declarations and introduce some Pick magic:

export interface Credentials {
  name: string;
  email: string;
  password: string;
}

First of all, this is far easier to read and manage.

Secondly, I prefer using an interface over a type unless I’m composing more complex types, which I don’t think “credentials” are particularly complex.

Using Pick, we can tell TypeScript just to pick those particular Keys from our existing Type (which could be an interface or type).

This allows us to cleverly construct a new type from using Pick, but only use the relevant properties (ignoring the others):

export interface Credentials {
  name: string;
  email: string;
  password: string;
}

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor() {}

  async create({ name, email, password }: Credentials) {...}

  async login({ email, password }: Pick<Credentials, 'email' | 'password'>) {...}

  async resetPassword({ email }: Pick<Credentials, 'email'>) {...}
}

Far cleaner, and all the types are kept in a single place. If you’re likely to reuse them, you can of course break them out into type keywords as well which I’ll show you momentarily.

🚨 Pro tip: Be careful not to confuse the 'email' | 'password' with a Union Type. In a Mapped Type such as Pick, this | syntax is more “and” instead of “or”.

JavaScript Array Methods eBook Cover

🎉 Download it free!

Ready to go beyond ForEach? Get confident with advanced methods - Reduce, Find, Filter, Every, Some and Map.

  • Green Tick Icon Fully understand how to manage JavaScript Data Structures with immutable operations
  • Green Tick Icon 31 pages of deep-dive syntax, real-world examples, tips and tricks
  • Green Tick Icon Write cleaner and better-structured programming logic within 3 hours

As an extra bonus, we'll also send you some extra goodies across a few extra emails.

If we were to in future change the Credentials interface, the new definitions will flow through the rest of the code, rather than us updating each Intersection Type manually.

Pick is a great utility Mapped Type that makes things lots easier for us, I highly encourage you to use it to your advantage to keep your codebase clean!

🕵️‍♂️ You can also check out the brief Pick documentation if you’d like to as well.

And promised, here’s how you can create new types with the resulting Pick types, which would allow you to use them elsewhere without repeating the same code.

export interface Credentials {
  name: string;
  email: string;
  password: string;
}

type LoginUser = Pick<Credentials, 'email' | 'password'>;
type ResetPassword = Pick<Credentials, 'email'>;

Either way, this is far easier to see! We also get added intellisense benefits with using an interface instead of a type.

Read more on Interfaces vs Types in a previous article I’ve put together on the subject - a bit more of a deep dive!

🙌 Oh and before you go, I’ve built a bunch of TypeScript Courses which might really help you level up your TypeScript skills even further. Check them out and see what else you can learn!

Check out the live example in StackBlitz, have a play around and see how it works:

Happy Picking, and thanks for reading!

Free eBooks:

JavaScript Array Methods eBook Cover

Ready to go beyond ForEach? Get confident with advanced methods - Reduce, Find, Filter, Every, Some and Map.

NestJS Build a RESTful CRUD API eBook Cover

Build your first NestJS app. With the CLI you'll learn the basics of real-world NestJS development.