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.
More Tips
Type Predicates
1 min
TypeScript 5.1 Beta is OUT!
2 mins
Don't use return types, unless...
4 mins
TypeScript 5.0 Beta Deep Dive
6 mins
Conform a Derived Type Without Losing Its Literal Values
1 min
Avoid unexpected behavior of React’s useState
1 min
Understand assignability in TypeScript
2 mins
Compare function overloads and generics
1 min
Use infer in combination with string literals to manipulate keys of objects
1 min
Access deeper parts of objects and arrays
1 min
Ensure that all call sites must be given value
1 min
Understand how TypeScript infers literal types
1 min
Get a TypeScript package ready for release to NPM in under 2 minutes
1 min
Use assertion functions inside classes
1 min
Assign local variables to default generic slots to dry up your code and improve performance
2 mins
Know when to use generics
2 mins
Map over a union type
1 min
Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig
1 min
Use generics to dynamically specify the number, and type, of arguments to functions
1 min
Use 'declare global' to allow types to cross module boundaries
2 mins
Turn a module into a type
2 mins
Create autocomplete helper which allows for arbitrary values
2 mins
Use deep partials to help with mocking an entity
1 min
Throw detailed error messages for type checks
1 min
Create a 'key remover' function which can process any generic object
1 min
Use generics in React to make dynamic and flexible components
1 min
Create your own 'objectKeys' function using generics and the 'keyof' operator
1 min
Write your own 'PropsFrom' helper to extract props from any React component
1 min
Use 'extends' keyword to narrow the value of a generic
1 min
Use function overloads and generics to type a compose function
2 mins
Decode URL search params at the type level with ts-toolbelt
2 mins
Use 'in' operator to transform a union to another union
2 mins
Derive a union type from an object
2 mins