Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Prohibition against prefixing interfaces with "I" #121

Closed
scottmmjackson opened this issue Dec 2, 2015 · 37 comments
Closed

Prohibition against prefixing interfaces with "I" #121

scottmmjackson opened this issue Dec 2, 2015 · 37 comments

Comments

@scottmmjackson
Copy link

The Typescript Handbook tells the developer not to prefix interfaces with I. This needs more detail. Lots of .NET developers are familiar with I-prefixed interfaces. Simply stating that the concept is broader is not sufficient. If it's an antipattern, let's describe why. If it's not an antipattern, then let's say "it is not necessary to prefix interfaces with I, and Typescript Contributors do X"

@RyanCavanaugh
Copy link
Member

I'm not entirely sure what more to write. .NET is the one with the rule (always prefix interfaces with I), not TypeScript. TypeScript code also generally shouldn't write names like lpcstrName like Win32 C code does. It's just a statement of "You shouldn't bring in this other framework's naming rules just because the keyword for the declaration is the same".

Any constructive ideas on how to phrase this?

@scottmmjackson
Copy link
Author

"It is not necessary to prefix interfaces with 'I', as is done in C#."

Otherwise, what it sounds like you mean is that prefixing with I is a great way to encounter the ancient demons of code collision or bad coding practices. Right now it says "Do not", which is prohibitory language, not advisory language.

If there is a recommended style (like postfixing with Interface or Type or the like), that would be even better to note, rather than the discouraged prefix.

@mhegazy
Copy link
Contributor

mhegazy commented Dec 3, 2015

not to sound pedantic, but necessary/not necessary is not the right word, i do not think it is necessary to add I in C# nor is it in TS. i would say "you shouldn't use 'I'" is more accurate.

@DanielRosenwasser
Copy link
Member

Agreed with @mhegazy.

DanielRosenwasser added a commit that referenced this issue Dec 5, 2015
Fix wording of interface naming conventions, fix #121
@robgha01
Copy link

robgha01 commented Oct 6, 2016

@mhegazy prefixing namespaces with I in c# is common sense how would you else like your code written using I distinguishes interfaces and abstracted classes ex: CarBase describes a abstract base for cars and the interface IAccelerate describes the method which incises the speed of the car not prefixing this with I means it could be anything i would never in the world work with code that dont prefix interfaces with I in c# its absurt.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 6, 2016

@robgha01 this is a style choice. you are free to write C# code with no I prefixes, as well as TS code with them. This is a style recommendation we make, and one we use in our internal code base. the compile does not enforce any rules regarding names of interfaces or classes.

@JonathanYates
Copy link

JonathanYates commented Mar 2, 2017

I 'IS' for Interface. Nothing to do with .Net (although common sense prevails there).

Reasons are obvious and I fail to understand why anyone would not prefix an interface with 'I'.

  1. Clearly identifies that it IS an interface.
  2. Clearly distinguishes between an interface and an implementation.
  3. What are you going to call the implementation if the interface is not prefix with I.
    e.g. Interface Foo. Err FooImpl as they do in Java. Please no!! IFoo and Foo makes it very clear.

I kind of feel the world has gone a little mad and lost it's marbles! Please prefix ALL interfaces with 'I' because 'I' IS for Interface.

@RyanCavanaugh
Copy link
Member

Everyone knows to follow C++ naming conventions, so the class will be called CFoo thus there is no conflict. 🙄

@Raketar
Copy link

Raketar commented Aug 1, 2017

Most complete answer for this topic I found in this stackoverflow answer:
https://stackoverflow.com/a/41967120/4676238

@UTGuy
Copy link

UTGuy commented Oct 28, 2017

I just ran across this issue and read @Raketar stackoverflow link. The first response is a very logical and reasoned answer. The ability to decipher an interface from an abstraction or implementation by simply seeing an "I" in front of it will speed up anybody trying to process what they are reading (instead of having to go to the file). In Berkov's post he says 'choose appropriate name for abstraction and concrete implementation' but then uses the implementation example 'FileBasedAutosuggestManager' and interface 'AutosuggestManager', yet 'FileBasedAutosuggestManager' could just as easily been an interface also... which seems to be overlooked here.

It appears this whole thread boils down to preference not correctness. Whether someone wants to write Async at the end of their methods to denote async/await is preference, or Base at the end of an abstraction. Languages borrow conventions all the time. It's what people get used to. If that helps speed up learning and development then use it, unless something better comes along. But this is one of the cases for me at least, there's not clear evidence that dropping the 'I' as a convention is more beneficial.

@RyanCavanaugh
Copy link
Member

I don't understand the confusion. Classes should always start with a three-letter prefix:

Your own classes should use three letter prefixes. These might relate to a combination of your company name and your app name, or even a specific component within your app. As an example, if your company were called Whispering Oak, and you were developing a game called Zebra Surprise, you might choose WZS or WOZ as your class prefix.

@scottmmjackson
Copy link
Author

Objective C Handbook?

@UTGuy
Copy link

UTGuy commented Oct 31, 2017

@RyanCavanaugh Theres no confusion, context is important. If someone is writing a pull request into typescript, you should be using typescript convention, .Net use "I" for interface.... etc. Cavanaugh is just establishing a convention for the library which is fine.

The whole "what about" argument for the three-letter prefix boils down to context IMO. If its the convention of the library to prefix three-letters (albeit a terrible one IMO for numerous reasons), that's the end of it. So you could either have a argument over the correctness of the pattern or you could state it's the preference for the library.

The difference between "I" for interface and the three-letter argument (for correctness sake), is the context in which the variables/classes exist. If the company "Whispering Oak" creates a game called "Zebra Surprise", the the resulting package would typically be name "zerbra-surprise.exe" (or w/e) under the "Whispering Oaks" directory... and one could make the argument that three-letter prefixes are unnecessary due to the context its in. Redundancies can and probably should be removed, that would be my argument, at least. Contrary to this, you cannot infer that an interface is an interface by using context clues, therefor adding an "I" would be a reasonable response.

@stasberkov
Copy link

@UTGuy
In my post on stackoverflow I just mentioned possible reasons why TypeScript team has guideline do not use I-prefix for interfaces.
When my team started using TS we also used I-prefix for interfaces. C# influence, I assume.
Then I read TypeScript team's guideline about not using I-prefix. It took me several weeks to realize it. I was eagerly searching for information why they have such rule.
After a time I realized: I-prefix for interfaces is a flaw (at least in TypeScript), it causes more problems than provides benefits.

There is one more reason for not using I-prefix. I call it "when in Rome..." rule (play by the rules of a used framework). TypeScript team has such guideline, Angular2+ has such guideline, rxjs is written in such manner.

@iam3yal
Copy link

iam3yal commented Dec 16, 2017

The prefix in the .NET world was never necessary it only added confusion, some people reads the prefix as if it is the pronoun I which is wrong.

@JonathanYates

Clearly distinguishes between an interface and an implementation.

In practice an interface name in the .NET world shouldn't match the implementation name.

Interfaces in the .NET world should be small and implementations should be composed of multiple interfaces and if you have a single interface that describes an implementation and you want to distinguish between them a better convention could have been something like this Engine (interface) and DefaultEngine (Implementation) even though it doesn't say much but I find it a lot better than IEngine and Engine, however, today some people do this IEngine and DefaultEngine where the prefix is really redundant.

Consumers shouldn't know whether Engine is an interface or an abstract class because this should be an implementation detail, you can always start with an interface and transition to an abstract class but because of the naming convention you can't do it and this is part of the reason we're going to have Default Interface Members but it is what it is. :)

That said, I still use the prefix I in .NET because I don't want to be the only one to break the rules and most importantly I don't want consumers to get confused so I follow what everyone does but I do think it was a mistake.

@santhony7
Copy link

I have been struggling with this as well. When I was a C# and ActionScript developer we always prefaced our interfaces with I and it was one of the first things I learned about TypeScript. I do understand the arguments "against" it but then I run into community standards like adding a $ at the end of observables. Obviously, we do seem to desire instant gratification in identifying things. I'm curious as to how often I am going to start writing "new Thing()" only to find out it is an interface and I can't do that. :-)

@Flamenco
Copy link

Ideally, you should always use an interface, and so dropping the prefix makes sense to me. Let the abstract and implementation classes be explicit with verbose prefix and/or suffix, and let the interfaces be the pure function name.

@leoskyrocker
Copy link

leoskyrocker commented Aug 14, 2018

@stasberkov Even in the above article he suggested using Contracts (via abstract class).
In the naming he actually used the "Contract" prefix.... I think every articles you posted are suggesting some prefixes/suffixes in their own naming schemes...

When thinking more about your example of SportsCar -> Car, in typescript it becomes:

class Car {
    startEngine(): void;
}

class SportsCar implements Car {
    startEngine() {
        console.log('Engine Starting...');
    }
}

While other develops can start coming in and use this car class by extending it:

class CoolerSportsCar extends Car { }

and he changes Car to be:

class Car {
    startEngine(): void {
        console.log('I have a default implementation');
    };
}

In this case, as people add additional behavior in the interface, how do we avoid breaking the original contract that other callers depend on?

(I am not even coming from the C# community but I just didn't see how removing the I in the name would solve any problems.)

@stasberkov
Copy link

@leoskyrocker

I am not even coming from the C# community but I just didn't see how removing the I in the name would solve any problems

  1. Name decoration is not needed in contemporary dev environments. It is atavism. Statement that prefix is helpful for immediately grokking (peeking) is an appeal to Hungarian notation. I prefix for interface name, C for class, A for abstract class, s for string variable, c for const variable, i for integer variable. I agree that such name decoration can provide you type information without hovering mouse over identifier or navigating to type definition via a hot-key. This tiny benefit is outweighed by Hungarian notation disadvantages and other reasons mentioned below.
  2. I-prefix violates encapsulation principle. Let's assume you get some black-box. You get some type reference that allows you to interact with that box. You should not care if it is an interface or a class. You just use its interface part (I from SOLID principle). Demanding to know what is it (interface, specific implementation or abstract class) is a violation of encapsulation.
  3. Protection from bad naming. It forces developers to choose distinguished names that emphasize implementaion differences. Naming things is hard. It is one of two hard things in Computer Science. Developers are lazy. If they can use Car->ICar scheme they will use it.
  4. Conformance. When in Rome principle. Major ts-based frameworks like Angular discorage using I prefix for interfaces. Rxjs also do not use I prefix.

@leoskyrocker
Copy link

It is necessary to come to a realization that the violation of encapsulation doesnt lie in the naming itself, but on the languages' restrictions. For example, in Java, there's no way to implements a class and you can only implements an interface. The violation of encapsulation automatically happens when someone tries to use an interface.

Yet, I have arrived at a unanswered question for myself: does it necessarily mean something is bad as soon as we coin it as a violation of some rules? In this case, we have seen no problems of having these language restrictions.

@giovannipds
Copy link

If you came here looking for answers as I did, just check TypeScript's handbook <3.

@fis-cz
Copy link

fis-cz commented Jan 29, 2020

@RyanCavanaugh I know it is bit old, could you maybe tell us why your team decided not to prefix interfaces with I? I mean, what was the reason?

I think thats because in TypeScript the interface is not just an pure object interface but it can be used to define interface to ctors, call signatures, indexable objects and maybe more I can't imaigine right now

@mishabarabolkin
Copy link

mishabarabolkin commented Feb 28, 2020

Indeed. Since the first comment was posted more than 4 years ago, we have not received clear answer. So why you decided that it's better to avoid using i-prefix for interfaces naming? Is there any significant reason or is it just the wishes of your team? I apologize for being straightforward

@orta
Copy link
Contributor

orta commented Feb 28, 2020

I'm not sure what you're after?

This question was answered right away by multiple team members, and the opinion of the team hasn't changed in the last 5 years to be honest.

I'm not entirely sure what more to write. .NET is the one with the rule (always prefix interfaces with I), not TypeScript. TypeScript code also generally shouldn't write names like lpcstrName like Win32 C code does. It's just a statement of "You shouldn't bring in this other framework's naming rules just because the keyword for the declaration is the same".

For example, we also don't prefix our types with T either:

type TThing = {}

You're all welcome to make your own decisions about this on a per-team basis, and if your teams come from C# then maybe that is keeping an I around, but there's no need to bring another language's conventions over when you can conform to JavaScript's conventions.

@rulatir
Copy link

rulatir commented Apr 1, 2020

@leoskyrocker

how do we avoid other developers from blurring the line of actual implementation and abstraction

-- clear naming? Actual implemenation must have in name what particular implemenation of abstraction it is. E.g. SportsCar->Car. Forbidding I prefix forces developers choosing distingished names. Not just Car -> ICar.

Car -> ICar cases, i.e. having an interface + a reference implementation that will be used directly 99% of the time (while leaving room for alternative implementations just in case), are WAY too common to disallow optimizing for.

@rulatir
Copy link

rulatir commented Apr 1, 2020

@leoskyrocker

  1. Name decoration is not needed in contemporary dev environments. It is atavism. Statement that prefix is helpful for immediately grokking (peeking) is an appeal to Hungarian notation.

Stop this slippery slope fallacy. Please. Just stop. No one will start writing 'lpcstr' in JS, let alone in TS.

  1. I-prefix violates encapsulation principle. Let's assume you get some black-box.

Yes, let's ASSUME you get some black-box, and let's stick to that assumption regardless of whether the box has "I" written on it or not.

  1. Naming things is hard.

... and what is hard is precisely what shouldn't be deliberately made harder.

  1. Major ts-based frameworks like Angular discorage using I prefix for interfaces. Rxjs also do not use I prefix.

That's their problem.

@f1am3d
Copy link

f1am3d commented Apr 5, 2020

@RyanCavanaugh
Simple example:

type FbEvent = 'post' | 'repost' | 'comment';    // Error: Duplicate identifier 'FbEvent'

export interface FbEvent {    // Error: Duplicate identifier 'FbEvent'
    type: FbEvent
    data: object
}

Why I must not use prefixes in similar cases?

type FbEvent = 'post' | 'repost' | 'comment';    // No errors

export interface IFbEvent {    //  No errors
    type: FbEvent
    data: object
}

-prefix violates encapsulation principle. Let's assume you get some black-box. You get some type reference that allows you to interact with that box. You should not care if it is an interface or a class. You just use its interface part (I from SOLID principle). Demanding to know what is it (interface, specific implementation or abstract class) is a violation of encapsulation.

@stasberkov, Emmm, no. It doesn't actually.

Encapsulation describes following things:

A language mechanism for restricting direct access to some of the object's components.

Prefixing does not prevent restricting direct access to some of the object's components.

A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data

Do prefixing somehow violates that rule? Of course not.
Moreover: Interfaces are barely related to the term Encapsulation. 😉

@christopheranderson
Copy link

@FlamesoFF in your case, I believe you've created a false dilemma. I wouldn't agree with the naming of your type FbEvent, regardless of I- prefix or not for the similarly named interface. Your event is composed of a type and some data. It would not make sense to name the type enumerating the potential values for type as the event itself, because it lacks data.

Normally, when modeling a type like this, I'd personally start with an anonymous type for FbEvent.type, like so.

export interface FbEvent {
    type: 'post' | 'repost' | 'comment';
    data: object;
}

Then, if I wanted to derive a type from FbEvent.type, I'd usually follow the pattern of combining the parent name and the property name, so FbEventType. Thus:

export type FbEventType = 'post' | 'repost' | 'comment';

export interface FbEvent {
    type: FbEventType;
    data: object;
}

Note, in this case, we're not naming FbEventType with a -Type suffix because it is a type, but because it is derived from the anonymous type of the FbEvent.type property (and thus not a suffix at all). If we renamed FbEvent.type to FbEvent.flavor, I'd change the FbEventType type name to FbEventFlavor. I also only do this when it makes sense. I prefer not to break out types like this unless necessary for avoiding lots of duplication, because it makes refactoring type to flavor or FbEvent to FacebookEvent also mean refactoring any types I derived from that name.

Note, I'm not saying the above should be a code guideline. I'm just saying that using an I- prefix on the interface to prevent name collision is a false dilemma, because it would be solved by more specific naming. Though, it does align with the Car -> ICar argument in the sense that using I- can lead to choices in design that would be better solved with more specific, appropriate names.

In general, I do think this argument boils down I- being a legacy of a legacy of Hungarian Notation (via COM/C#), and you can agree with Hungarian Notation or not, but it does seem odd that some language concepts get prefixes/suffixes, and some do not. You could argue that interfaces are special and need the prefix, but we don't need the rest of HN. That could be refuted by the rather large existing code bases in TypeScript that don't follow the rule, and get along just fine. Add on to the pile that architects of the C# language think the I- prefix is a mistake, and there's heavy weight against changing this guideline given lack of evidence of harm.

@microsoft microsoft locked as resolved and limited conversation to collaborators May 13, 2020
i9or referenced this issue in murelain/movie-cat-app Apr 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests