How to Name your Types

Here are my top 4 rules for how to name your types.

Never pluralize: Unless your type is an array type, you should make it singular - even if it's a union of members.

Casing: Choose a different casing between your values and your types. This helps stop syntax highlighting getting confused.

Type Parameters: prefix your type arguments with T. If you've got only one type argument, you can use T. Otherwise, be more descriptive with your parameter names.

Avoid Unnecessary Prefixes: Prefixes like IUser and TOrganization might feel useful, but they're mostly just holdovers from the Java days.

Transcript

Matt Pocock: 0:00 What's up, wizards? Today, we're going to be looking at how you should name your types. Every time you create a type, you're going to have to be thinking, "What do I name this? What rules do I use?" I've got a bunch of little heuristics that I use when I'm naming types, and I'm going to show you some optional stuff that you can maybe adopt if you want to.

0:14 The first rule is never pluralize. Let's imagine that we've got a union type like this. We have three routes, user, admin/user, and admin. It feels natural, because these are a collection of routes, to name it routes. Let's imagine that we have a function called goToRoute. This route parameter here only ever represents one route, and so we've got this weird mismatch between the routes and the route.

0:34 If you think about it, this union type up here only ever represents one route. Sure, these are a collection of different routes, but really, it's only describing the possibility of a single route. The correct way to name these is route, not routes.

0:47 Let's imagine that we had to make an array of these routes. You can define it as route array, like this. If this was written as routes array, it sort of reads OK, but it kind of indicates that maybe routes is itself an array. Naming everything as a singular is a lot cleaner.

1:01 If you wanted to, you could turn routes into an array itself. Now, routes represents an array of route. This, I think, is pretty clean too. There you go. Rule number one, make sure everything is singular except for array types. Yes, in the king's English, it's pronounced root, not rout, you heathens.

1:18 Next up, always use a different case between your variables and your types. Let's go back to our goToRoute example. It is perfectly valid to rename this as lowercase. Because TypeScript understands that this route is on the runtime and this route is on the type level, it doesn't conflict.

1:32 You can even declare a variable in the same scope as the route, but here you can see that the syntax highlight starts getting confused. If we change this back to Pascal case, you can see that the syntax highlighting on the variable now looks correct.

1:43 It works in reverse too. If I name this uppercase Route, then it turns green. Where you can, you should use a different casing for your variables and your types.

1:50 Let's look at generic type parameters now. Let's imagine that I've got this generic type called response. We have a data in T and we have an error, which is always an error. For simple types like this, I will generally keep this as a single letter T, but changing it to TData is also perfectly valid.

2:05 In general, I'll always prefix it with a T because data doesn't look like a generic to me, so T or TData are both perfectly valid. One place I will never use T is if this contains multiple type arguments. This T, U thing up here is actually a convention. You can keep going T, U, V, etc, but here, it starts to look like pure maths instead of maintainable code.

2:26 What I prefer to do is rename this as TError and this one as TData. This means that the signature of the type is a lot easier to read. You may want to be a bit stricter and force your team to give these more descriptive names. That's totally fine too. For me, as long as they're prefixed with T or they are T itself, then it's fine, but T, U, V, W, X, Y Z, that can go to hell.

2:44 This final one is one that I don't really recommend that you do. Let's imagine that we have two types here. We have a user type and an organization interface here. In some places, I will see people at TUser and IOrganization. This indicates that this is a type and this is an interface.

2:59 I don't really see the point in this, especially not if you're using I and T here. It seems strange. If you eventually want to change this over to a type, then you'll also need to change the name and everywhere it's used. I don't see what benefit you're getting from seeing it's an interface from the name.

3:13 I think this is another convention carried over from the Java days. Personally, I don't see why it's still relevant. You can just hover over the name of the thing to figure out if it's an interface or a type anyway.

3:22 There you go, folks. Those are my rules for how to name your types. Keep things singular. Use a different case from your variables. Prefix type arguments with T, and be sensible. Hopefully, you know that one already.

3:34 Thanks for watching, folks. I have a beginner's TypeScript tutorial that is free on totaltypescript.com. It is an absolute banger. It will take you through everything you need to know in order to get a job with TypeScript. Go and check it out.

3:45 I'll have another video that you can watch here and a little face that you can subscribe to here. What did you think of this video? What rules did I miss? What do you do in your team that you think is a little bit weird? What do you want me to diagnose next? What should I make a video on next? Too many questions. I'll see you very soon.

How to name your types in TypeScript can be a tricky business. Matt takes you through his opinionated heuristics for how to decide.

Discuss on Twitter

More Tips

Play Type Predicates

Type Predicates

1 min

Play TypeScript 5.1 Beta is OUT!

TypeScript 5.1 Beta is OUT!

2 mins

Play Don't use return types, unless...

Don't use return types, unless...

4 mins

Play TypeScript 5.0 Beta Deep Dive

TypeScript 5.0 Beta Deep Dive

6 mins

Play Conform a Derived Type Without Losing Its Literal Values

Conform a Derived Type Without Losing Its Literal Values

1 min

Play Avoid unexpected behavior of React’s useState

Avoid unexpected behavior of React’s useState

1 min

Play Understand assignability in TypeScript

Understand assignability in TypeScript

2 mins

Play Compare function overloads and generics

Compare function overloads and generics

1 min

Play Use infer in combination with string literals to manipulate keys of objects

Use infer in combination with string literals to manipulate keys of objects

1 min

Play Access deeper parts of objects and arrays

Access deeper parts of objects and arrays

1 min

Play Ensure that all call sites must be given value

Ensure that all call sites must be given value

1 min

Play Understand how TypeScript infers literal types

Understand how TypeScript infers literal types

1 min

Play Get a TypeScript package ready for release to NPM in under 2 minutes

Get a TypeScript package ready for release to NPM in under 2 minutes

1 min

Play Use assertion functions inside classes

Use assertion functions inside classes

1 min

Play Assign local variables to default generic slots to dry up your code and improve performance

Assign local variables to default generic slots to dry up your code and improve performance

2 mins

Play Know when to use generics

Know when to use generics

2 mins

Play Map over a union type

Map over a union type

1 min

Play Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig

Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig

1 min

Play Use generics to dynamically specify the number, and type, of arguments to functions

Use generics to dynamically specify the number, and type, of arguments to functions

1 min

Play Use 'declare global' to allow types to cross module boundaries

Use 'declare global' to allow types to cross module boundaries

2 mins

Play Turn a module into a type

Turn a module into a type

2 mins

Play Create autocomplete helper which allows for arbitrary values

Create autocomplete helper which allows for arbitrary values

2 mins

Play Use deep partials to help with mocking an entity

Use deep partials to help with mocking an entity

1 min

Play Throw detailed error messages for type checks

Throw detailed error messages for type checks

1 min

Play Create a 'key remover' function which can process any generic object

Create a 'key remover' function which can process any generic object

1 min

Play Use generics in React to make dynamic and flexible components

Use generics in React to make dynamic and flexible components

1 min

Play Create your own 'objectKeys' function using generics and the 'keyof' operator

Create your own 'objectKeys' function using generics and the 'keyof' operator

1 min

Play Write your own 'PropsFrom' helper to extract props from any React component

Write your own 'PropsFrom' helper to extract props from any React component

1 min

Play Use 'extends' keyword to narrow the value of a generic

Use 'extends' keyword to narrow the value of a generic

1 min

Play Use function overloads and generics to type a compose function

Use function overloads and generics to type a compose function

2 mins

Play Decode URL search params at the type level with ts-toolbelt

Decode URL search params at the type level with ts-toolbelt

2 mins

Play Use 'in' operator to transform a union to another union

Use 'in' operator to transform a union to another union

2 mins

Play Derive a union type from an object

Derive a union type from an object

2 mins