How to change the type of output for a property filter in typescript

Published on January 30, 2021 - Tagged: #typescript

Follow me on twitter for more posts like this

If you have an iterable filter on a property in typescript you might have a slightly different model coming out of the filter based on the filter condition.

By setting the types correctly you can potentially save having to add manual typing hints in whatever follows the filter.

It’s easier to show this with code so see below!

Thanks to one of my colleagues for suggesting this one in a code review.

The problem


type Car = {
  brand: string,
  color: string,
  tireWidth: number.
  spareTire?: SpareTire // note this is optional
}

// If we have this filter where we filter out the items where a property is undefined.
// Then we know that the property must be defined in the map. But the typescript type will still
// be undefined so we have to supply a hint ("!") to tell typsctipt our property is present
 const spareTireInfo = myCars
            .filter(
                (car) =>
car.spareTire !== undefined
            )
            .map(
                (car) =>
                    ({
                        spareTireAge: car.spareTire!.age //here we have to hint the undefined property is present
                        tireWidth: car.tireWidth
                    } )
            );

This isn’t too bad here with just one property being accessed but it would be tedious if you had more. It’s also an issue if you use eslint and warn on unnecessary type assertions (like ”!”). If you do that you have to add an ignore for each property.

We can prevent this by specifying the type expected from the filter.

type Car = {
  brand: string,
  color: string,
  tireWidth: number.
  spareTire?: SpareTire // note this is optional
}

type WithSpareTire = {
    spareTire: SpareTire; // note this is not optional anymore
};

const spareTireInfo = myCars
            .filter(
                (car): car is Car & WithSpareTire => // here we hint the output type
car.spareTire !== undefined
            )
            .map(
                (car) =>
                    ({
                        spareTireAge: car.spareTire.age // now we don't have to provide the "!" hint anymore
                        tireWidth: car.tireWidth
                    } )
            );

Hope it helps!

Darragh ORiordan

Hi! I'm Darragh ORiordan.

I live and work in Sydney, Australia building supporting happy teams that create high quality software for the web.

I also make tools for busy developers! Do you have a new M1 Mac to setup? Have you ever spent a week getting your dev environment just right?

My DevShell tooling will save you 30+ hours configuring your dev environment with all the best modern tools. Get it here

https://darraghoriordan.gumroad.com/l/devshell


Read more articles like this one...

List of article summaries

#typescript

How to write an ESLint plugin in TypeScript

I use NestJS at my day job. It’s a complicated framework sometimes and there are lots of things that devs “just have to remember” or there will be bugs in your application that you won’t see until runtime.

I wanted to remove this cognitive load from NestJS engineers so that they can focus on valuable work instead. I wrote an ESLint plugin to alert developers directly in their IDE or editor when these common issues exist - (Available on NPM) https://www.npmjs.com/package/@darraghor/eslint-plugin-nestjs-typed

Here is what I learned about writing ESLint plugins in typescript for typescript while building the plugin.

#typescript

Create an only ever true boolean type in typescript

Integrating with an API where a boolean can only be undefined or true I needed to type it. It’s easy enough but I just wanted to jot it down in case any one else needs this in the future.

#typescript

Copying missing files during a typescript build on deploy

If you build your nodeJS project using typescript, it’s important to know that the typescript compiler tsc will only include files that are .js or .ts.

If you have an issue where you deploy or build a typescript project and you get a file not found issue or similar, it’s probably because you missed that typescript does not process these kinds of files for you.

If you need to include files like XML (.xml) or images in your typescript project build output, you will have to copy them manually before or after the build process.

This is one way to copy assets in a typescript build.