A note on 'everything is singular'. I thought of another case - bags of options. Props, Options, Settings - all to me indicate a 'config object', not an array. Weird how language works.
I suppose we've gotten very used to seeing these words pluralized, so when we see them as singular (Prop, Option, Setting) I, for one, consider it to mean a part that is extracted from that pluralized group. Options is not Option pluralized, but instead Option is an extracted unit of Options. So the plural becomes "default" and a singular version is the one that needs extra context. Does that make sense?
@mattpocockuk Hi Matt, could you suggest me how to name the following definitions properly? Suppose i have the following enum-like object: const UserRole = { ADMIN: "admin", CUSTOMER: "customer", MODERATOR: "moderator" } as const; And now i also want to define a type for this: type UserRole = typeof UserRole[keyof typeof UserRole]; Is it ok to have both UserRole object and UserRole type?
Hello Matt. I use the "I" prefix because I don't always remember the exact name of the interface and use ide hints. If I write "IU", then Ide will tell me only the names of the interfaces, because they all start with "I", for example "IUser, ITelegramUser, IGetUserResponse". Without the prefix, I'm more likely to see component and function names in tooltips.
As a C# developer, I use I to indicate interfaces, partially because it's a language standard, but also because an implementation can have the same name as the interface. UserRepository - Unclear if it's an implementation or an interface. IUserRepository - Very clear that it's an interface, which subsequently means that UserRepository is an implementation.
@@Dojan5 why would you name the implementation the same as the interface though? that's a thing I've never understood about C#. shouldn't the interface be the thing you're deriving your implementation from? this naming scheme implies the opposite, that the interface is just a clone of its implementation, but as an interface
@@darxoonwasser The interface is a contract, an outline of what you expect in a class, but not necessarily how. Since a decently recent C# update you *can* add code to interfaces, but I've never actually seen this in practise and I personally think it's a bit of an antipattern. Due to its nature as a contract, you know that it has a Get() method that returns a User, but you don't really care if that user was newed up in the method or if it was fetched from the database, or an API, you just care that your request for a user returned a user. This is useful in Dependency Injection, where you inject an Interface rather than an actual implementation of something. In doing so, when running unit tests on your code, you can inject dummy dependencies that still fulfil the interface requirements (like just conjuring up a user) and ensuring that the code you actually want to test (your class) is working properly, without a dependency causing problems, say, a database connection going wrong and causing delays and errors in the tests in one run, but working the next.
Great video as always, I really like idea of properly naming your the parameters to your generic types so much so that I've gone and updated the names in my codebase!
I often use IInterface or TType because they may interfere with React components as they might be similar e.g. component could be User and the interface for a user object may be IUser.
2:44 Thank you for this! My team have been doing this for a while and I've been trying to convince them to stop since I had the exact same thought as you
The prefix really helps when you import types and components. Say you have a Comment component and a Comment type. It's hell trying to import that as VSCode auto complete will get easily confused. Especially since the naming convention is the same
Why is it hell? Import will pull in both if they're in the same module, and if they're aren't that's just the usual import collision which is easy enough to handle. In that specific example, if is likely to lead to a problem, I see which is more likely to be widely used and therefore the "default", and change either the component to CommentView or similar, or the type to CommentDetails or similar, assuming I don't have a better option for naming them. Certainly IComment would be completely wrong, as that implies that Comment implements IComment.
I’m totally fine with T for generic argument, R for generic return value, and K, V for key and value generic types. So function foo(arg: T): R is fine or Record where K : string | number | symbol
I use “I” prefix for interfaces as I only use an interface to describe classes. Usually variables are camel cased and types are pascal cased; so they are distinguishable. Classes are pascal cased and interfaces are as well; so I use “I” prefix to distinguish them
TypeScript is my go-to language for web development! I absolutely love adding prefixes to code. It brings clarity and consistency to my projects. Using 'E' for enums, 'I' for interfaces, and 'T' for types helps me quickly identify and understand different elements of the codebase
Lately, I’ve started to use the I-prefix for interfaces in React, since then I won’t run into Chat the interface and Chat the component etc. That couldn’t come up with a better example on the spot.
@MattPocock great content, love your channel! As for the "T" and "I" prefixes on types and interfaces, they might come in handy in big React projects. Often times, developers find themselves having to deal with both a User type and a User component, hence having a prefix might avoid name collisions. Not a fan of those myself, just adding a little input here
I think it's pretty clear which one is a type and which one is a component based on context and import, as well based on information your IDE provides. If it doesn't distinguish between those, then you should make it or find another IDE. The User type cannot be used as a value, nor can the component be used as a type (except if you happen to use class components, in which case, change them to functional components).
this is a holdover from my Java days, too, but I tend to use Interfaces on Classes (or objects) almost exclusively. If an interface contains mostly methods than it should be an interface, not a Type - and likewise Type is a bit more like a Struct in my mind. With that, I tend to name my Interfaces like "X-able": "Archiveable", "Hashable", "Comparable", etc. I'll broaden this to any kind of actionable-noun pair if I really stuggle to find the right name, but I think it jives well with the intent of an interface, particularly if it implements multiple interfaces: "This object is Hashable and Archivable with all the methods that entails"
I like to have all my stuff to be able to contribute something. Therefore appending -able to anything isn't really saying anything useful. E.g. in C even primitive types like _int_ and _float_ would be comparable as well as presumably both archivable and hashable too. This trait doesn't depend on providing an "interface" as discussed in that particular language, allthough in some other language that may conceivably be the case. An interface is a "thing" or concept, and a noun is (by definition) what is used to name such a thing or anything else. Now, since humans love to categorize everything, we probably have a noun for that category as well, and the noun "interface" is likely a good candidate. We can include that noun too if that aspect of the "thing" is an important one (which it probably is here), and then we end up with names like ArchiveInterface, HashInterface and ComparisonInterface. I like short names for frequent and common things, otherwise the code tends to become too verbose and may hamper rather than ease readability, so using a short prefix like I (IArchive, IHash, IComparison) is a pragmatic and workable solution. Another solution can be found in many natural languages themselves, including English. The language already has come up with many infixes/suffixes for said categorization and to identify them, and there are some in particular to mark an _agent_ of some action (verb) too: -or, -er. This is usually what the purpose of an interface is, so then the interfaces can be named like Archiver, Comparator, Worker, Sorter, Hasher, Operator, etc. The problem with this (especially for non-native speakers of English) is that many of these suffixes have become distorted or merged through time, so they may be ambigious or not easily spotted or recognized. For instance, it is tempting to also use such nouns to name the implementation of the interface: FileArchiver, MyComparator, Worker(!), Sha256Hasher, LessOperator, ClickOperator, ... This may be considered a significant argument against such a naming scheme.
@@benhetland576 to your first point about primitives already being hashable comparable, and archivable. you realize those were just examples to illustrate the grammar, right? as to your other points: I think you're saying my convention wouldn't work for you? I can't really make out what you're saying except "I don't like this" I don't think an "-er" suffix for an interface would work for me: to me, that's a noun - better suited for class and instance names. a "worker" is a, well, worker... which might be streamable, socketable, threadable (again, not serious examples, just examples)
@@ThatRobHuman Nah yeah, I realize they were just examples, and I actually like your concept too. The point is that the -able suffix makes a verb into an adjective, which would be appropriate to describe a _property_ of something, not to name the "something" (type, interface, class, object) itself. Arguably an interface is not a property or type trait, but "thing" in and by itself, which is why it breaks the grammar. It only _appears_ to work because English has lost so many of the word endings that it no longer marks a distinction between different word classes in most cases, thus the same word can act as a verb, noun, adjective, adverb, ... according to interpretation. It all boils down to semantics. Yet -able is not ambigious in what it produces (an adjective) nor in what it modifies (a verb). If you start with a term that still remains uninterpretable as a verb (say "window" perhaps?) you see that tacking on an -able for an interface to interact with it no longer works the intended way. _WindowInterface_ or even _IWindow_ may work, but _Windowable_ not so well. So in your widget collection you may have other things you want interact with like a (clickable) button, a list box of some items, or a field for entering something. To name their interfaces _Buttonable, Listable, ListBoxable, EditFieldWidgetable_ or _Fieldable_ may not work so well. E.g. the list widget itself is not typically what is listable, though its content is. You can button something, but that's not normally what you do with a button widget.
@@benhetland576 see, I would totally use "Windowable" despite it not being a "real" word, because it is a thing that can behave like a Window, but I take your point nonetheless: it doesn't hold up when you've got an interface that describes multiple noun implementations like data structures, either - HashMap, TreeMap, and LinkedHashMap implement Map - not Mappable. Perhaps there's a bit of a distinction to be had: "Interfaces as mechanism for composition assurance" vs "Interfaces that could otherwise be an Abstract Class" - two different (albeit closely related) use-cases that happen to both use Interfaces - the former are the "N-able" syntax, whereas the latter I'd totally use the "I" prefix, or just leave it as a meaningfully generic noun, like "Map".
Great video! I guess for TS you can omit the I prefix for interfaces, since your IDE can show you that it is an interface. In C++ though, there is no interface keyword, but it is essentially a pure virtual class. Here I recommend the I prefix.
I have a few opininons for these advices I want to share. For pluralization, the true question is whether the type represent a unit or an aggregation of values. A Route between different possibilities denoted by the union is really only a single value at a time, a unit, while a list of routes is an aggregation of those values. Another case where it can help disambiguate the intention for a type is with object type, where a Vector or a User, while composite, represents a unit of correlated data, while an Options or Props object is a bag of named data that are not neccessarily very correlated. For casing, it's more of a precision/theory about syntax highlighting than an opinion, the reason it starts highlighting your constant/variable as a type if a type of the same name exists is probably due to classes in JS. A class being technically a `let ClassName = a constructor function` (and a bit more, making them not just syntactic sugar), it is a variable, and in typescript classes also declare an interface type of the same name. I suspect that syntax highlighting for typescript assumes that a variable with the same name as a type is the type's class constructor and higlights it as such. For type parameters, while I agree that giving more explicit names to type parameters is better than basic single letter names (Result better than Result or Result), just like function parameters, I think prefixing them with a T is not necessary or making the type parameter more legible. I'd compare it to prefixing function parameters with a p which would just end up making it anoying. Lastly about knowing if a type is an interface or type alias, there is a value with the guarantees and different functionality you have with interfaces over type aliases, but yes, the prefix is unneccessary since we have tooling to inspect types and it usually tells which one it is. Programming in TS usually does not have the same experience as programming in C using a stock Vim decades ago, it's time to let go the habits of that time.
I almost always try to give full names for generics, however sometimes it doesn't make sense. However I've not been prefixing generics. This lead to some awkward situations with name collisions and also just not being sure, so that's helpful.
even java people dont do the "I" thing anymore 😂 but i see it used a lot in c# still. i think we got rid of hungarian notation for a reason. express intent not types.
The Interface "I"-Prefix is one of those things that are deeply engraved in our company guidelines. I don't really feel strongly about the rule itself - but I aggree, that it's kinda pointless in TS. In C# however it is often necessary because often you have Interfaces that exactly represent an existing class. I hate it - but sadly in C# it is required to be able to mock those classes in unittests.
You're right. It seems this is more like a naming practice was bring from mainly strong typed oriented to objects languages (such as C# and Java) to TS, that eventually got adopted by some people, but yeah, it's kinda pointless in TS.
I never let my code (or its readability) depend on features not in the code itself, such as which editor or viewer I happen to have available or its configuration, font selection, color vs b&w etc. All these tend to change over time, and they are nice and helpful features, just that I really don't want to depend on them.
I've found that adding an I prefix to interfaces gives better code completion options. When I want to reference a type, I type "I" and VSCode autocomplete finds all types in my project.
I also agree with this. An additional reason is to differentiate classes with interfaces, especially when you have a class of the same name implementing an interface of the same name. I have seen a lot of blogs and whatnot say that the “I” prefix is dead and should not be used, but I am not convinced.
one of the most helpful video about TS for our community))) what about generic types - I think that you can use T and U, but if you have more - use normal name, please)
Type is a class right? So I would name the interface to that type the exact same thing, but with an I in front. I don't generally use a prefix for classes themselves, as the Capitalization and the location it's used is more than enough, if you don't also have an IDE that color marks it. However, it can be nice to call your interfaces the exact same thing as the class, but with an I in front, to easily see where it belongs.
I've got a question. Look, you recomend to name types with capital letter, but zod objects are also named from capital lerrer and zod types, how to distinguish them in code,?
I prefixes for interfaces help a lot when you’re outside the IDE, like reviewing PR’s or just looking at a repo because you understand the intent is to use an interface over a concrete type. But a T prefix for types? I’ve never even seen that and it would be totally confusing given the conventions for generics.
We prefix interfaces with I on classes, so class MyClass implements IMyClass Wasn't a fan at first but the convention makes it easy to find the class instance or the interface
Really appreciate your typescript tip videos. And I’ll definitely start prefixing my type params for generics. I agree, it’s more readable this way and I can easily know what’s going on if I’m away from the project - thanks 👍🏽
Could you go over points regarding using an ORM vs not using one? and when opting to not use an ORM. which tools would be helpful for connection pooling, migrations, caching, etc..
i think putting "I" in front of intarfaces came from name collisions because in the past you couldn't have an exported variable/class named the same as your interface, but now you can so I see no point in using these prefixes anymore.
The only thing I find difficult is when I have a type that has the same name as a component I have. Let's say I have a component called Form, and it consists out of FormElements (also a component). I have an API that returns json like so: { form: {name: "name", formElements: []} } For this I create a response type called FormResponse. But then the inner types for Form and for FormElement. Usually I just call them Form, and FormElement. However, that sometimes gets confusing with the components, so then I call them FormType and FormElementType. And sometimes you also have request types, so you have FormRequest and FormElementRequest. Idk really.
For that initial example, a good example would be the type number. If a variable that stored a single number was of type numbers, people would automatically intuit that must be an array.
Step 1. name each type after the sha-2 hash of the md5 hash of the sha-1 hash of the literal text used after "=" if defining a type or inside the "{ }"'s if using an interface. Step 2. tell no one. Step 3. Rewrite the entire code base. Step 4. ??? Step 5. Guarantee job security on the project (you are self employed and are currently hiring yourself) Step 6. 💵💵💵PROFIT! 💵💵💵
I've been thinking about name collisions between react components and types, because both start with a capital. So far I've been abstained from hungarian notation, but I feel like it could be useful again. Idk which of types or components should get the prefix/suffix tho.
in my current project, I have properties like this from a lot of my types: thisType, thatType, fooType etc., which basically is a string union on which "type" a certain object is. It's kind of confusing if I don't add a T before the type's name. (2nd reason: type name and component name is conflicting)
The point of typescript (or one of them) is to be able to easily refactor so having to change a name should not be an inhibitor to anything. I like to use `TUser` because it creates a clear delineation between Classes and Types. const someUser: User = new User("1", "Avi") const someTUser: TUser = {id: "1", name: "Avi"}
What are the practical benefits of this approach? Like why do you want to known if something is a class or a type? Did you known that you can do this for example? class User { constructor(public id: string, public name: string) {} } const someUser: User = {id: "1", name: "Avi"}
Having to hover over things to get their types is encumbersome. Code readbility is judged by the ability to read it, not the ability to have your IDE help you understand something by hovering over it. Ex. You wouldn't want to name a boolean anything other than is or are or whatever verbage you come up with the is similar.
Great tips! Do you have any recommendations for when the backend data type is the same as a React component type? In your example, Organization, but we also have a React component named that. Any thoughts? Thanks again for your work!
Sounds like you should rethink your component name, something like OrganizationDisplay, since "Organization" is easily understood as a data type, does not make a lot of sense to name a component that way, it also makes it hard to "guess" what the Organization component do, might be a table, a label, a form, no way to know by just glancing at the code
I personally think the prefix stuff is garbage. Even in the generics types you mention with TData and TError. If I want a generic type I just name it T or U (actually I name it A and B precisely to look like Maths, but that's not really significant). The reason for a generic is that they can be anything, so leaving it as just T indicates that. If I want my T to be some type of Data then I use *Constraints* So it'd be Response That reads better and forces you to define your Data and Error types
The only reason to use IInterface is for people dealing with class interfaces in OOP. I think it's not a worry for most of us since a lot of people have ditched classes entirely at this point.
even there it doesn't make sense it's just that Microsoft doesn't know how to use Hungarian notation, invented its own version of it and as such gave it a bad name in the entire industry
I think we can generally agree that people stopped using underscore for protected members (like private _thing: Record), Hungarian notation (like private _lTimestamp: BigInt or public bEnabled: boolean) for types and intentions; and the same I think we need to deprecate IInterfaces. It does not carry information about symbol or variable contents and purpose; it carries meta-information. And this information is redundant declaration of already existing symbol declaration. With language servers and syntax highlighting, it’s not needed as the authentic meta information can be extracted from the code for the most languages. Moreover, small rearrangements and refractors could actually cause bugs as the name can misrepresent the variable. The only thing that kind of justifies it is a struggle to name both interface and implementation, but it’s actually a red flag: do you need an interface here if you can’t figure out what is the difference between your interface and implementation.
One curve ball for you. You have a class and an interface that the class implement. What do you call the interface? Since both the class name and the interface are in Pascal I think calling the interface Ixxx is a valid? Please let me know if there is a better way to do that. Thanks! Love your content, man. Keep the videos coming! ❤
Which are public (or, more public)? If it's both, why are they separate? If it's just so you can mock it, you don't in general need to have an interface for that in TS. If it's so you can have a general interface that people use and a default implementation that should only be used as "const foo: IFoo = new Foo()", instead expose a "function createFoo(): IFoo", it's much more flexible. Most of the time you don't even need classes at that point, just return an object! Otherwise it doesn't really matter what you call the private one, but the public one should be the "simpler" name. You can call the private class FooImpl if you're really stuck.
haha you know us so well, called me out on the pronunciation before i could think of typing a smartass comment :P great video! whats your thoughts on typing the same thing for different contexts? Like `User`, where you might have a db Model type, a document type, and a typed api response?
I know this is about TS, but in C# it's convention to prefix interfaces with I, and to me it's actually a really good idea. Because in Java, List is an interface so they had to call the actual concrete class ArrayList which seems unnecessary. Whereas in C# List is the class you use and the interface would always begin with I so would never conflict
It doesn't seem unnecessary. It's just a Java convention. Implementations express intent, not syntax. You can say that ArrayList uses array under the hood, while LinkedList uses links between objects. This convention makes the code more readable and understandable.
I'm actually not getting that syntax highlight issue. const Route: Route highlights correctly for me in VSCode. I'm wondering though, even if it was a highlighting issue if CamelCase is the convention for components and classes and if I'm using the same convention for naming types, should I break convention or submit an issue to VSCode about incorrect highlighting? I mean, isn't that a bug if the IDE is highlighing a const or let as a type? Maybe this is another case for prefixing the type like TRoute? IDK, I'm a junior just trying to do the right thing.
I disagree with "never pluralize" rule. I often end up with complex Map or Set assigned to a type and it usually makes sense to pluralize it. Always for Set, often for Map.
it is better to use T, I and E prefixes, because it can significantly reduce amount of type names. And also you can nicely group these types with each other.
I am route. I've started using TData with generics when there are multiple types like in your example. One thing I do get stuck on is naming types when they are similar to their final variable names, still haven't figured out how to get around that yet. Particularly with React Contexts: type AuthContext = {...} const AuthContext // oops
I still don't understand why people use ALL_UPPER_CASE for a const in TS. You can't reassign it so you don't need the "documentation" of ALL_UPPER_CASE -- a holdover from C++.
At 3:15, It is not convention from Java days, It is convention from microsoft. One of the main reason why I hate working with dotnet because of these stupid conventions. UpperCamelCase for everything, Class, Method, even properties. This is stupid. In Java, convention is to add descriptors at the end only if necessary like OrgInterface, OrgDto etc. But only if it is guaranteed to conflict, like having both Interface and Adapter for same thing.
Hello Matt, nice beginners course. May I ask you a question about a piece of code found on the typescript handbook page. Under chapter "Template Literal Types" they have a piece of sample code whereby the declare a function "makeWatchedObject". Could you make a video about an implementation if this function? It looks very interesting to me.
I see NO issue preceding types with its "intent" ala "TUser" or "IUser" - when you are looking at a bunch of code and its formatting etc.. desctructing etc.. being able to eyeball the "T" or the "I" helps the brain to formalize what is going on better. I don't understand when people have these opinions.. its a letter, on a word... it doesn't matter, as long as it has intent for the user.
What would be the appropriate name for a type that represents an array of objects received in response, but where the (react) components only use individual objects, e.g. after mapping? Typically, I use the type "Items = {...}[]" for the array and "type Item = Items[number]" within the component. Is there a more optimal solution?
A note on 'everything is singular'. I thought of another case - bags of options.
Props, Options, Settings - all to me indicate a 'config object', not an array.
Weird how language works.
Awesome video. Quick question how do you deal with situations where you omit or extend parts? I havent figured out a decent way myself yet.
I suppose we've gotten very used to seeing these words pluralized, so when we see them as singular (Prop, Option, Setting) I, for one, consider it to mean a part that is extracted from that pluralized group. Options is not Option pluralized, but instead Option is an extracted unit of Options. So the plural becomes "default" and a singular version is the one that needs extra context. Does that make sense?
Personally I'd save the plural version for objects and special cases. For Route[] just use Route[].
i'm not hearing a difference
@mattpocockuk
Hi Matt, could you suggest me how to name the following definitions properly?
Suppose i have the following enum-like object:
const UserRole = {
ADMIN: "admin",
CUSTOMER: "customer",
MODERATOR: "moderator"
} as const;
And now i also want to define a type for this:
type UserRole = typeof UserRole[keyof typeof UserRole];
Is it ok to have both UserRole object and UserRole type?
preffix it with T, got it
TT TU TV
Hello Matt. I use the "I" prefix because I don't always remember the exact name of the interface and use ide hints. If I write "IU", then Ide will tell me only the names of the interfaces, because they all start with "I", for example "IUser, ITelegramUser, IGetUserResponse". Without the prefix, I'm more likely to see component and function names in tooltips.
As a C# developer, I use I to indicate interfaces, partially because it's a language standard, but also because an implementation can have the same name as the interface.
UserRepository - Unclear if it's an implementation or an interface.
IUserRepository - Very clear that it's an interface, which subsequently means that UserRepository is an implementation.
@@Dojan5 why would you name the implementation the same as the interface though? that's a thing I've never understood about C#. shouldn't the interface be the thing you're deriving your implementation from? this naming scheme implies the opposite, that the interface is just a clone of its implementation, but as an interface
@@darxoonwasser The interface is a contract, an outline of what you expect in a class, but not necessarily how.
Since a decently recent C# update you *can* add code to interfaces, but I've never actually seen this in practise and I personally think it's a bit of an antipattern.
Due to its nature as a contract, you know that it has a Get() method that returns a User, but you don't really care if that user was newed up in the method or if it was fetched from the database, or an API, you just care that your request for a user returned a user.
This is useful in Dependency Injection, where you inject an Interface rather than an actual implementation of something. In doing so, when running unit tests on your code, you can inject dummy dependencies that still fulfil the interface requirements (like just conjuring up a user) and ensuring that the code you actually want to test (your class) is working properly, without a dependency causing problems, say, a database connection going wrong and causing delays and errors in the tests in one run, but working the next.
@@Dojan5UserRepository interface
implementations:
SqlUserRepository, MongoUserRepositiry, PgSqlUserRepository
Great video as always, I really like idea of properly naming your the parameters to your generic types so much so that I've gone and updated the names in my codebase!
I often use IInterface or TType because they may interfere with React components as they might be similar e.g. component could be User and the interface for a user object may be IUser.
This happened to me today. I think I'd rather use prefixes for interfaces and types.
As a proud heathen, I'll say it must pronounced as "Route" not "Root"
😅
But King's english says "Root"
Must be.
@@KiwiCoke the king was a product of incest and pedophilia… probably shouldn’t be the standard for anything 😬😬😬
Rowte
2:44 Thank you for this! My team have been doing this for a while and I've been trying to convince them to stop since I had the exact same thought as you
I like it. Especially things like TData, TError, etc. for improved readability.
The prefix really helps when you import types and components. Say you have a Comment component and a Comment type. It's hell trying to import that as VSCode auto complete will get easily confused. Especially since the naming convention is the same
Why is it hell? Import will pull in both if they're in the same module, and if they're aren't that's just the usual import collision which is easy enough to handle.
In that specific example, if is likely to lead to a problem, I see which is more likely to be widely used and therefore the "default", and change either the component to CommentView or similar, or the type to CommentDetails or similar, assuming I don't have a better option for naming them. Certainly IComment would be completely wrong, as that implies that Comment implements IComment.
I usually use the T prefix for type parameters if I want to give them a more verbose name so it doesn't shadow actual type definitions
I’m totally fine with T for generic argument, R for generic return value, and K, V for key and value generic types. So function foo(arg: T): R is fine or Record where K : string | number | symbol
"It's pronounced 'root' you heathens"
proceeds to pronounce it as 'rawt' (1:45) 😂
Great video as always Matt!
The routes example was eye-opening
You get a prize for being the first person I've heard say "the King's English" this century.
I use “I” prefix for interfaces as I only use an interface to describe classes. Usually variables are camel cased and types are pascal cased; so they are distinguishable. Classes are pascal cased and interfaces are as well; so I use “I” prefix to distinguish them
e.g.
class Organization implements IOrganization
I saw the thumbnail, I thought you were gonna tell that we should use I for interfaces, and T for types. I was relieved to hear your thoughts about it
TypeScript is my go-to language for web development! I absolutely love adding prefixes to code. It brings clarity and consistency to my projects. Using 'E' for enums, 'I' for interfaces, and 'T' for types helps me quickly identify and understand different elements of the codebase
Lately, I’ve started to use the I-prefix for interfaces in React, since then I won’t run into Chat the interface and Chat the component etc.
That couldn’t come up with a better example on the spot.
@MattPocock great content, love your channel!
As for the "T" and "I" prefixes on types and interfaces, they might come in handy in big React projects. Often times, developers find themselves having to deal with both a User type and a User component, hence having a prefix might avoid name collisions.
Not a fan of those myself, just adding a little input here
Thats right. Just commented about that!
I think it's pretty clear which one is a type and which one is a component based on context and import, as well based on information your IDE provides. If it doesn't distinguish between those, then you should make it or find another IDE.
The User type cannot be used as a value, nor can the component be used as a type (except if you happen to use class components, in which case, change them to functional components).
@@dealloc agreed.
I think the problem in that case is having and interface and a type named the same way. that does not make a lot of sense, right?
@@darkarie No that makes a lot of sense, because they are distinct from each other (value vs. type) while describing the same thing.
Good shit, agree with everything. Although I usually use "FooT" for generics instead of a "T" prefix.
this is a holdover from my Java days, too, but I tend to use Interfaces on Classes (or objects) almost exclusively. If an interface contains mostly methods than it should be an interface, not a Type - and likewise Type is a bit more like a Struct in my mind.
With that, I tend to name my Interfaces like "X-able": "Archiveable", "Hashable", "Comparable", etc. I'll broaden this to any kind of actionable-noun pair if I really stuggle to find the right name, but I think it jives well with the intent of an interface, particularly if it implements multiple interfaces: "This object is Hashable and Archivable with all the methods that entails"
I like to have all my stuff to be able to contribute something. Therefore appending -able to anything isn't really saying anything useful. E.g. in C even primitive types like _int_ and _float_ would be comparable as well as presumably both archivable and hashable too. This trait doesn't depend on providing an "interface" as discussed in that particular language, allthough in some other language that may conceivably be the case. An interface is a "thing" or concept, and a noun is (by definition) what is used to name such a thing or anything else. Now, since humans love to categorize everything, we probably have a noun for that category as well, and the noun "interface" is likely a good candidate. We can include that noun too if that aspect of the "thing" is an important one (which it probably is here), and then we end up with names like ArchiveInterface, HashInterface and ComparisonInterface. I like short names for frequent and common things, otherwise the code tends to become too verbose and may hamper rather than ease readability, so using a short prefix like I (IArchive, IHash, IComparison) is a pragmatic and workable solution.
Another solution can be found in many natural languages themselves, including English. The language already has come up with many infixes/suffixes for said categorization and to identify them, and there are some in particular to mark an _agent_ of some action (verb) too: -or, -er. This is usually what the purpose of an interface is, so then the interfaces can be named like Archiver, Comparator, Worker, Sorter, Hasher, Operator, etc. The problem with this (especially for non-native speakers of English) is that many of these suffixes have become distorted or merged through time, so they may be ambigious or not easily spotted or recognized. For instance, it is tempting to also use such nouns to name the implementation of the interface: FileArchiver, MyComparator, Worker(!), Sha256Hasher, LessOperator, ClickOperator, ... This may be considered a significant argument against such a naming scheme.
@@benhetland576 to your first point about primitives already being hashable comparable, and archivable. you realize those were just examples to illustrate the grammar, right?
as to your other points: I think you're saying my convention wouldn't work for you? I can't really make out what you're saying except "I don't like this"
I don't think an "-er" suffix for an interface would work for me: to me, that's a noun - better suited for class and instance names.
a "worker" is a, well, worker... which might be streamable, socketable, threadable (again, not serious examples, just examples)
@@ThatRobHuman Nah yeah, I realize they were just examples, and I actually like your concept too. The point is that the -able suffix makes a verb into an adjective, which would be appropriate to describe a _property_ of something, not to name the "something" (type, interface, class, object) itself. Arguably an interface is not a property or type trait, but "thing" in and by itself, which is why it breaks the grammar. It only _appears_ to work because English has lost so many of the word endings that it no longer marks a distinction between different word classes in most cases, thus the same word can act as a verb, noun, adjective, adverb, ... according to interpretation. It all boils down to semantics.
Yet -able is not ambigious in what it produces (an adjective) nor in what it modifies (a verb). If you start with a term that still remains uninterpretable as a verb (say "window" perhaps?) you see that tacking on an -able for an interface to interact with it no longer works the intended way. _WindowInterface_ or even _IWindow_ may work, but _Windowable_ not so well. So in your widget collection you may have other things you want interact with like a (clickable) button, a list box of some items, or a field for entering something. To name their interfaces _Buttonable, Listable, ListBoxable, EditFieldWidgetable_ or _Fieldable_ may not work so well. E.g. the list widget itself is not typically what is listable, though its content is. You can button something, but that's not normally what you do with a button widget.
@@benhetland576 see, I would totally use "Windowable" despite it not being a "real" word, because it is a thing that can behave like a Window, but I take your point nonetheless: it doesn't hold up when you've got an interface that describes multiple noun implementations like data structures, either - HashMap, TreeMap, and LinkedHashMap implement Map - not Mappable.
Perhaps there's a bit of a distinction to be had: "Interfaces as mechanism for composition assurance" vs "Interfaces that could otherwise be an Abstract Class" - two different (albeit closely related) use-cases that happen to both use Interfaces - the former are the "N-able" syntax, whereas the latter I'd totally use the "I" prefix, or just leave it as a meaningfully generic noun, like "Map".
The content that I would love to watch more! Thanks Matt😊
Great video! I guess for TS you can omit the I prefix for interfaces, since your IDE can show you that it is an interface. In C++ though, there is no interface keyword, but it is essentially a pure virtual class. Here I recommend the I prefix.
I have a few opininons for these advices I want to share.
For pluralization, the true question is whether the type represent a unit or an aggregation of values. A Route between different possibilities denoted by the union is really only a single value at a time, a unit, while a list of routes is an aggregation of those values. Another case where it can help disambiguate the intention for a type is with object type, where a Vector or a User, while composite, represents a unit of correlated data, while an Options or Props object is a bag of named data that are not neccessarily very correlated.
For casing, it's more of a precision/theory about syntax highlighting than an opinion, the reason it starts highlighting your constant/variable as a type if a type of the same name exists is probably due to classes in JS. A class being technically a `let ClassName = a constructor function` (and a bit more, making them not just syntactic sugar), it is a variable, and in typescript classes also declare an interface type of the same name. I suspect that syntax highlighting for typescript assumes that a variable with the same name as a type is the type's class constructor and higlights it as such.
For type parameters, while I agree that giving more explicit names to type parameters is better than basic single letter names (Result better than Result or Result), just like function parameters, I think prefixing them with a T is not necessary or making the type parameter more legible. I'd compare it to prefixing function parameters with a p which would just end up making it anoying.
Lastly about knowing if a type is an interface or type alias, there is a value with the guarantees and different functionality you have with interfaces over type aliases, but yes, the prefix is unneccessary since we have tooling to inspect types and it usually tells which one it is. Programming in TS usually does not have the same experience as programming in C using a stock Vim decades ago, it's time to let go the habits of that time.
Great video Matt !! Always a pleasure learning from a wizard 🧙
Awesome video as always! On the fun side did I hear 1:44 Uppercase ROUTE :D
thanks for clarify this which is what i was wondering all today.
we need a 5 hour long video/course with Matt speaking non-stop
I almost always try to give full names for generics, however sometimes it doesn't make sense.
However I've not been prefixing generics. This lead to some awkward situations with name collisions and also just not being sure, so that's helpful.
Oh wow, this TData, TError is so brilliant! I think I will change some of my code now...
even java people dont do the "I" thing anymore 😂 but i see it used a lot in c# still. i think we got rid of hungarian notation for a reason. express intent not types.
Love your videos and also the way you present them. Thanks Matt
The Interface "I"-Prefix is one of those things that are deeply engraved in our company guidelines. I don't really feel strongly about the rule itself - but I aggree, that it's kinda pointless in TS. In C# however it is often necessary because often you have Interfaces that exactly represent an existing class. I hate it - but sadly in C# it is required to be able to mock those classes in unittests.
You're right. It seems this is more like a naming practice was bring from mainly strong typed oriented to objects languages (such as C# and Java) to TS, that eventually got adopted by some people, but yeah, it's kinda pointless in TS.
For the generic types, I think it's better to add different color rules for them. I have different colors for classes, generics enums and types.
I never let my code (or its readability) depend on features not in the code itself, such as which editor or viewer I happen to have available or its configuration, font selection, color vs b&w etc. All these tend to change over time, and they are nice and helpful features, just that I really don't want to depend on them.
@@benhetland576 that's what I call an intelligent approach
I've found that adding an I prefix to interfaces gives better code completion options. When I want to reference a type, I type "I" and VSCode autocomplete finds all types in my project.
I also agree with this. An additional reason is to differentiate classes with interfaces, especially when you have a class of the same name implementing an interface of the same name. I have seen a lot of blogs and whatnot say that the “I” prefix is dead and should not be used, but I am not convinced.
one of the most helpful video about TS for our community)))
what about generic types - I think that you can use T and U, but if you have more - use normal name, please)
Type is a class right? So I would name the interface to that type the exact same thing, but with an I in front. I don't generally use a prefix for classes themselves, as the Capitalization and the location it's used is more than enough, if you don't also have an IDE that color marks it. However, it can be nice to call your interfaces the exact same thing as the class, but with an I in front, to easily see where it belongs.
I've got a question. Look, you recomend to name types with capital letter, but zod objects are also named from capital lerrer and zod types, how to distinguish them in code,?
The prefix stuff you said comes "from the Java days" is actually called "hungarian notation" and much older than Java.
I prefixes for interfaces help a lot when you’re outside the IDE, like reviewing PR’s or just looking at a repo because you understand the intent is to use an interface over a concrete type. But a T prefix for types? I’ve never even seen that and it would be totally confusing given the conventions for generics.
Thanks Matt, useful and concise 👌
We prefix interfaces with I on classes, so
class MyClass implements IMyClass
Wasn't a fan at first but the convention makes it easy to find the class instance or the interface
Really appreciate your typescript tip videos. And I’ll definitely start prefixing my type params for generics.
I agree, it’s more readable this way and I can easily know what’s going on if I’m away from the project - thanks 👍🏽
Could you go over points regarding using an ORM vs not using one? and when opting to not use an ORM. which tools would be helpful for connection pooling, migrations, caching, etc..
i think putting "I" in front of intarfaces came from name collisions because in the past you couldn't have an exported variable/class named the same as your interface, but now you can so I see no point in using these prefixes anymore.
In some cases, prefixing interfaces with letter I makes sense - take react for example. "Post" would be a component and "IPost" would be an interface
The only thing I find difficult is when I have a type that has the same name as a component I have.
Let's say I have a component called Form, and it consists out of FormElements (also a component).
I have an API that returns json like so: { form: {name: "name", formElements: []} }
For this I create a response type called FormResponse.
But then the inner types for Form and for FormElement.
Usually I just call them Form, and FormElement. However, that sometimes gets confusing with the components, so then I call them FormType and FormElementType.
And sometimes you also have request types, so you have FormRequest and FormElementRequest.
Idk really.
Cool channel! Keep up, man, quality content!
For that initial example, a good example would be the type number. If a variable that stored a single number was of type numbers, people would automatically intuit that must be an array.
Step 1. name each type after the sha-2 hash of the md5 hash of the sha-1 hash of the literal text used after "=" if defining a type or inside the "{ }"'s if using an interface.
Step 2. tell no one.
Step 3. Rewrite the entire code base.
Step 4. ???
Step 5. Guarantee job security on the project (you are self employed and are currently hiring yourself)
Step 6. 💵💵💵PROFIT! 💵💵💵
I've been thinking about name collisions between react components and types, because both start with a capital. So far I've been abstained from hungarian notation, but I feel like it could be useful again. Idk which of types or components should get the prefix/suffix tho.
Just do `import * as React from "react";` and you're golden, now it's `React.Component`. No collisions.
how to make the name refactor without actual to use the find and replace like the wat it is shown on the video?
Good stuff Matt, ur the goat 🎉
So If I have an array list of something like user list, then the name for this will be "userList" right?
Is prefixing interfaces with I a Java thing? I only know it from C#.
I use "root" for specific roadways, and "raot" for derived paths like in code.
thanks for sharing your wisdom Matt :)
in my current project, I have properties like this from a lot of my types: thisType, thatType, fooType etc., which basically is a string union on which "type" a certain object is. It's kind of confusing if I don't add a T before the type's name. (2nd reason: type name and component name is conflicting)
The point of typescript (or one of them) is to be able to easily refactor so having to change a name should not be an inhibitor to anything. I like to use `TUser` because it creates a clear delineation between Classes and Types.
const someUser: User = new User("1", "Avi")
const someTUser: TUser = {id: "1", name: "Avi"}
What are the practical benefits of this approach? Like why do you want to known if something is a class or a type?
Did you known that you can do this for example?
class User { constructor(public id: string, public name: string) {} }
const someUser: User = {id: "1", name: "Avi"}
Awesome short video
1:44 What did you say? You heathen 😁
Why do you even need to add prefixes to types and interfaces, we are not writing C# here
Is there any eslint rule to apply this awesome name convention?
Having to hover over things to get their types is encumbersome. Code readbility is judged by the ability to read it, not the ability to have your IDE help you understand something by hovering over it. Ex. You wouldn't want to name a boolean anything other than is or are or whatever verbage you come up with the is similar.
Matt, what’s the difference between ‘type’ and ‘interface’?
ruclips.net/video/zM9UPcIyyhQ/видео.html
Great tips! Do you have any recommendations for when the backend data type is the same as a React component type? In your example, Organization, but we also have a React component named that. Any thoughts? Thanks again for your work!
Sounds like you should rethink your component name, something like OrganizationDisplay, since "Organization" is easily understood as a data type, does not make a lot of sense to name a component that way, it also makes it hard to "guess" what the Organization component do, might be a table, a label, a form, no way to know by just glancing at the code
I personally think the prefix stuff is garbage. Even in the generics types you mention with TData and TError. If I want a generic type I just name it T or U (actually I name it A and B precisely to look like Maths, but that's not really significant).
The reason for a generic is that they can be anything, so leaving it as just T indicates that. If I want my T to be some type of Data then I use *Constraints*
So it'd be Response
That reads better and forces you to define your Data and Error types
The only reason to use IInterface is for people dealing with class interfaces in OOP. I think it's not a worry for most of us since a lot of people have ditched classes entirely at this point.
It doesn't make sense for class interfaces either
Interfaces in TypeScript are not really restricted classes or OOP.
even there it doesn't make sense
it's just that Microsoft doesn't know how to use Hungarian notation, invented its own version of it and as such gave it a bad name in the entire industry
classes are so 2016
I think we can generally agree that people stopped using underscore for protected members (like private _thing: Record), Hungarian notation (like private _lTimestamp: BigInt or public bEnabled: boolean) for types and intentions; and the same I think we need to deprecate IInterfaces. It does not carry information about symbol or variable contents and purpose; it carries meta-information. And this information is redundant declaration of already existing symbol declaration. With language servers and syntax highlighting, it’s not needed as the authentic meta information can be extracted from the code for the most languages. Moreover, small rearrangements and refractors could actually cause bugs as the name can misrepresent the variable.
The only thing that kind of justifies it is a struggle to name both interface and implementation, but it’s actually a red flag: do you need an interface here if you can’t figure out what is the difference between your interface and implementation.
Everyone should move to typescript now
One curve ball for you. You have a class and an interface that the class implement. What do you call the interface? Since both the class name and the interface are in Pascal I think calling the interface Ixxx is a valid? Please let me know if there is a better way to do that. Thanks! Love your content, man. Keep the videos coming! ❤
Which are public (or, more public)? If it's both, why are they separate?
If it's just so you can mock it, you don't in general need to have an interface for that in TS. If it's so you can have a general interface that people use and a default implementation that should only be used as "const foo: IFoo = new Foo()", instead expose a "function createFoo(): IFoo", it's much more flexible. Most of the time you don't even need classes at that point, just return an object!
Otherwise it doesn't really matter what you call the private one, but the public one should be the "simpler" name. You can call the private class FooImpl if you're really stuck.
*Spot on!* I 100% agree… except for the pronunciation of _"routes"._ Matt clearly didn't watch enough American TV as a child.
haha you know us so well, called me out on the pronunciation before i could think of typing a smartass comment :P great video!
whats your thoughts on typing the same thing for different contexts? Like `User`, where you might have a db Model type, a document type, and a typed api response?
I know this is about TS, but in C# it's convention to prefix interfaces with I, and to me it's actually a really good idea. Because in Java, List is an interface so they had to call the actual concrete class ArrayList which seems unnecessary. Whereas in C# List is the class you use and the interface would always begin with I so would never conflict
It doesn't seem unnecessary. It's just a Java convention. Implementations express intent, not syntax. You can say that ArrayList uses array under the hood, while LinkedList uses links between objects. This convention makes the code more readable and understandable.
1:45 - you heathen!
Should we capitalise interface names?
Yep
I'm actually not getting that syntax highlight issue. const Route: Route highlights correctly for me in VSCode. I'm wondering though, even if it was a highlighting issue if CamelCase is the convention for components and classes and if I'm using the same convention for naming types, should I break convention or submit an issue to VSCode about incorrect highlighting? I mean, isn't that a bug if the IDE is highlighing a const or let as a type? Maybe this is another case for prefixing the type like TRoute? IDK, I'm a junior just trying to do the right thing.
I disagree with "never pluralize" rule. I often end up with complex Map or Set assigned to a type and it usually makes sense to pluralize it. Always for Set, often for Map.
I always prefix interfaces with I, types with T and enums with E. Also, full names in generics only. Can't stop me 😎
Yeah it just doesn’t make sense to me without the prefixes. Particularly in NestJS, where OOP is heavily used.
it is better to use T, I and E prefixes, because it can significantly reduce amount of type names. And also you can nicely group these types with each other.
Hungary annotation is a error people do when don't know how to name things.
Very bad when some rules follow this, like Microsoft java
I am route.
I've started using TData with generics when there are multiple types like in your example.
One thing I do get stuck on is naming types when they are similar to their final variable names, still haven't figured out how to get around that yet. Particularly with React Contexts:
type AuthContext = {...}
const AuthContext // oops
Agree with everything here.
What’s the origin of naming generics as T? Shouldn’t it be G for generic?
T is for "Template". This comes from language C, where you often see something like:
template
class TemplatedClass
{
private T _value;
};
Unneeded prefixes come from C, when you have a class and a interface with the same name
The weirdest thing I saw is using the ISomething convention in Swift, where there's technically no interfaces
Just made me update my codebase... again!
I still don't understand why people use ALL_UPPER_CASE for a const in TS. You can't reassign it so you don't need the "documentation" of ALL_UPPER_CASE -- a holdover from C++.
At 3:15, It is not convention from Java days, It is convention from microsoft. One of the main reason why I hate working with dotnet because of these stupid conventions. UpperCamelCase for everything, Class, Method, even properties. This is stupid.
In Java, convention is to add descriptors at the end only if necessary like OrgInterface, OrgDto etc. But only if it is guaranteed to conflict, like having both Interface and Adapter for same thing.
And also make sure to call Route as Root 😅
Hello Matt, nice beginners course. May I ask you a question about a piece of code found on the typescript handbook page. Under chapter "Template Literal Types" they have a piece of sample code whereby the declare a function "makeWatchedObject". Could you make a video about an implementation if this function? It looks very interesting to me.
Could you ask in my Discord? mattpocock.com/discord
3:13 Java doesn't actually use that convention. The first time I ever saw that convention was in C#, so I think that's where it's coming from.
From that we can infer that all we know is that it was introduced no later than C# but at some time _after_ Fortran :-)
Thanks
1:45 You heathen ! xD
I see NO issue preceding types with its "intent" ala "TUser" or "IUser" - when you are looking at a bunch of code and its formatting etc.. desctructing etc.. being able to eyeball the "T" or the "I" helps the brain to formalize what is going on better. I don't understand when people have these opinions.. its a letter, on a word... it doesn't matter, as long as it has intent for the user.
roots or routes or rauts
What would be the appropriate name for a type that represents an array of objects received in response, but where the (react) components only use individual objects, e.g. after mapping? Typically, I use the type "Items = {...}[]" for the array and "type Item = Items[number]" within the component. Is there a more optimal solution?
type Item = {...}
type Items = Item[]
At work we don't use the convention of 'I' as an interface name prefix and it causes confusion imo
2:23 kind of a weird criticism to say that code looks like math when type theory is part of mathematics.
What vs code theme are you using?
Default!
@@mattpocockuk lmao haven't used default in so long I can't even recognize it anymore. Thanks.
thanks
Why not always use interface?
interfaces can't express all the things that types can, like union types.