The common misconception about TypeScript I hear a lot is - TypeScript is more OOP than JavaScript, TypeScript is more like Java, C#, was made for OOP programmers, it emphasizes classes and inheritance.
One of the last examples of such misconception being shared was part of quite popular article - TypeScript Tutorial: A step-by-step guide to learn TypeScript. Below quote from the article
TypesScript is an Object oriented programming language whereas JavaScript is a scripting language
Such a false statement in one of the most popular articles in dev.to about TypeScript 😔 . I decided to try to fight 💪 with these statements, and show you that TS is not in any bit more object oriented than JS itself.
TS has classes and inheritance so it's more OOP
TypeScript has classes, but JavaScript also has them. Take a look
// JS🟨
class User {
#name
constructor(name) {
this.#name = name;
}
}
const user = new User('Tom');
The same part in TS
// TS🟦
class User {
#name: string
constructor(name: string) {
this.#name = name;
}
}
const user = new User('Tom')
Any difference from additional type annotations? Don’t think so. Have you spotted private fields? Yes they are in both, as private fields went to stage 3 of ECMAScript standard.
Inheritance
There for both, consider
// JS🟨 and TS🟦
class Admin extends User{
#type = 'admin'
}
const admin = new Admin('Tom');
What is TS version of the above? The same… yes thanks to type inference I don’t need to change a bit. Where is the difference then? There is none
TypeScript type system emphasize OOP
That is true that TS has concept of interface, concept familiar for people working with statically typed object oriented languages like Java or C#. But TypeScript also has alternative syntax for types, and it's typical for functional languages, it is based on algebraic data types.
Instead of using interface
and extends
interface X extends Y {x: number}
you can use type
and intersection operator &
type X = Y & {x: number}
And you get the same result!
Check out below two equivalent versions of the same types definition
{
// interface version - familiar for Java/C#
interface User {
type: string
name: string
}
interface Admin extends User {
type: 'admin'
}
interface Moderator extends User {
type: 'mod'
}
function test(u: User) {
return u;
}
const admin: Admin = {
type: 'admin',
name: 'Tom'
}
test(admin) // admin can be used as user
}
{
// algebraic types version - familiar for functional programmers Haskell, Elm
type User = {
type: string
name: string
}
type Admin = User & {
type: 'admin'
}
type Moderator = User & {
type: 'mod'
}
function test(u: User) {
return u;
}
const admin: Admin = {
type: 'admin',
name: 'Tom'
}
test(admin) // admin can be used as user
}
You don’t need to use any interfaces in TS, you can do everything by type
and type operators like intersection and union. Yes really!
Note Did you know that original idea of object oriented programming had nothing about inheritance. Alan Kay who had made this term was focusing on encapsulation and message passing.
Functional programming in TypeScript is hard
This last one is outside of the original argument, but if not OOP, then natural choice is Functional programming, so if we resign from classes we will most probably write functions and data transformations in the functional style.
Is then functional programming harder in TS than in JS? Yes it is slightly, but fortunately there are tools for that, most famous functional libraries for JS are fully typed, so if you use for example Ramda, there are types for it. Also there are specially made libraries for TS like fp-ts, which represent pure statically functional languages type constructs and utilities. So yes, we can go fully functional!
Note With newest feature of TS 4.0 - variadic tuple types, FP is slightly simpler to model!
From where then the misconception came from?
Probably there are few sources
- TS creator is the same person who made C#
- TS had classes and private fields before JS
- Type notation (interfaces, generics) looks like in Java, C#
First is rather wrong, as a person who made one language no needs to make other languages the same. Second is only historically true, but we have 2020, don’t we? Third is only about grammar, yes looks similar but it has nothing if the language is object oriented or not.
And to be clear TypeScript is object oriented language, but object orientation is not in any way better than in JavaScript itself. Historically that was true, as TS introduced classes, private fields and inheritance when there was no such equivalent in JS. But now it is not true, everything related to object orientation exists in JS, TypeScript only adds type level to it.
TypeScript is JavaScript with additional static types level, both are multi-paradigm programming languages. Next time if somebody will tell you TS is only for OOP, tell him that it's nothing more than a lie.
Top comments (34)
For me the current implementation of JavaScript is a not a real OOP language because it lacks the encapsulation which the most important thing.
As you said in the article, private properties will come to JS with "#", till this day TS remains a real OOP language than JS.
It is all about protecting state, if FP language like Haskell or F# have immutability to protect the state, OOP languages do it with encapsulation.
The misinformation on the JS community is huge, for some reason. A) You don't need private properties/methods for a language to be OOP. A language isn't more "OOP" than other. It's like being turing-complete. B) Encapsulation doesn't mean having private attributes/methods.
Also, you can do OO without even classes, AND have private properties. What about:
Sure is doable like you said, but I have couple of concerns about your example:
What about when
private
is not initialized withhello
value but needs to object have to be constructed using external data ?What about performance when you have thousands of objects to create with closure?
I will be more than happy to read what is the correct meaning of encapsulation and how to do it?
I already do encapsulation (and private members) with classes(or prototypal inheritance if you will) inside modules with the help of the WeakMap
I don't understand why you would do this.
If you want to break a program, you can break it one way or another, so why try to chase the perfect level of encapsulation? Most languages who support encapsulation better than JS, still allow access through reflection. It's an endless cat and mouse game. To what end?
In the end, it's important that your code communicates how it should be used,
that the right way is most convenient and well surfaced, and the wrong way is harder.
private
works just fine to achieve exactly that and other modifiers likereadonly
etc.The only imo minor inconvenience of
private
compared to#
is collision. Python solves that by prefixing the variable name with_ClassName_
, transparently for you. You can do the same manually. Again it communicates that this variable should be considered as private state to the said class.Sure
#
just makes it more convenient, so that's nice, but definitely not a requirement to me.Nice hack to use WeakMap, but to me it's a waste of effort, increased maintenance hurdle/cost, cognitive load, and maybe even performance. Each much more important than achieving the perfect level of encapsulation imo.
Patrick Roza, thank your for the replay, in my example I'm talking in the context of the current JS implementation not the next JS or TS, for sure typescript solved the issue for now with private properties/methods.
I use encapsulation mainly to avoid shared mutating state issue and avoid an example like the following:
I can
freeze
or useObject.defineProperty
to achieve it, the later is more waste of effort.I don't think that using
WeakMap
s has a big performance impact compared to closures.I see, in TS trying to
delete obj.someProp
wheresomeProp
is markedreadonly
will be prevented by compiler.yea I just noticed that in vanilla JS you are kind of left to the harder options like closures or Weakmap.
At the same time, JSDoc may be helpful too, as said communication is the most important part imo, achievable by:
_myprivate
,_MyClass_myprivate
etc/** @private */
Editor support is of course very helpful, and in that, I think TypeScript as a supported standard is perhaps very helpful.
I agree, I use the example above for domain modeling with JS on nodejs, not in every part of my applications.
As you said, communication is important so I started switching to typescript.
+1 for the JSDoc.
Do you know what sucks about typescript in the style of OOP.
private AND #
I had hoped private would become equal to #
I am probably not understanding the details yet because # is new. None the less, we now have fake privacy and real privacy.
Title ...
... then In article body:
In my view this statement undermines the title. I would also observe that slightly is an understatement. Functional style TypeScript requires a much better grasp of TypeScript's typing meta-language - to a degree that isn't usually necessary when practicing a class-based object-oriented style (example: Learn Advanced TypeScript).
Once we accept that in TypeScript the class-based object-oriented style is the path of least resistance (according to: "make the right thing easy and the wrong thing hard") I think it is fair to say that TypeScript skews the choice of implementation towards class-based object-orientation much more than JavaScript does.
In Dependency Injection revisited (2018) (Blog post) Mark Seeman juxtaposes F# code against the somewhat equivalent C# code which looks like a verbose mess. Functional-style TypeScript is often reminiscent of that C# mess.
So I don't think that stating that TypeScript favours class-based object-orientation a lot more than JavaScript is too far off the mark. It takes a lot more determination to pursue a functional style in TypeScript than it does in JavaScript.
What's more insidious about this is that TypeScript's perceived OO-ness over JavaScript is taken by the mainstream as further corroboration that class-based object-orientation is the "true software development paradigm" - even when there are hints that we're moving away from OO.
Original object-orientation dates back to Simula (1962) and Simula 67 had classes and inheritance - i.e. it was class-based. Alan Kay's statement was made in 1998, some 30 years later and identifies Carl Hewitt's Actor Model as his mental model. At OOPSLA '97 he was quoted as saying: "I made up the term 'object-oriented', and I can tell you I didn't have C++ in mind" - but it's unclear whether he actually originated the term.
The big issue is that the mainstream currently uses "object-oriented" when they are actually talking about "class-oriented" - i.e. classes being used exclusively to create objects.
However you can work with objects without needing classes:
and considering:
... so class-based object-orientation seems to have always been TypeScript's primary priority.
More to the point with TypeScript you are confined to practicing Guerilla-FP because TypeScript is sanctioned while other more suitable but niche statically typed functional to-JS transpilers are not:
Thanks for mentioning the history. I already mentioned that originally TS had classes earlier than JS had them, that is true. Also I don't see a big difference between using class-based and not classed based OOP. Class is just definition of some class of objects, you can make it by closure sure, but fundamentally there is no difference, as OOP is mostly about encapsulation, and this is Kay way of thinking. The second school teaches that OOP is about inheritance and classes, and this goes from C++ and Stroustrup. I will not argue about definition here.
This article was showing that the same OOP you can do in JS and in TS, so how you can state that TS is more object oriented if there is no real difference? Latest years shows that TS is going more into FP because that is what community demands. You can write TS without any class, and as I mentioned I am doing that successfully many years. I said FP is little harder as FP in JS has dynamic origins, it is based on LISP. Adding types to that is not easy task, but I think TS made a great progress with that.
Also about your last two links, it has nothing to TS, you can do function based OOP in TS. But why? I don't see a point in trying to avoid classes if you do OOP, I mean the only reason to avoid them is more like allergy after being too much exposed to Java. Creating objects by constructors being simple function is ok, but in the end of the day we achieve the same result. Even more "class" is just syntax sugar over setting prototype, yes the famous JS prototype which nobody wanted to use.
I have nothing against doing OOP without classes, but saying that it is something better is overstatement, they are two sides of the same coin.
And also pay attention I didn't write article "TypeScript the FP language", and this is what you are trying to argue with. I said that TS is multi-paradigm as JS is.
In class-based languages the object's "membership" is static - i.e. an object cannot change "classes" during it's lifetime. In JavaScript an object's capabilities can be augmented after construction - effectively changing its "class".
DCI (Data Context Interaction) for example needs objects to dynamically present roles while not changing their identity. Static class membership of mainstream class-based OO languages gets in the way, requiring workarounds. This lead to trygve.
So whether or not you see "lifetime class membership" as a feature for objects depends on your particular needs.
Erlang (and independently the Actor model) uses a shared-nothing asynchronous message passing system. So data-hiding isn't an objective but simply the result of sharing nothing.
Other than that many FP languages don't care about data-hiding but simply respect the notion of a opaque data type when necessary. As Rich Hickey observed:
"And if you have a notion of “private”, you need corresponding notions of privilege and trust. And that adds a whole ton of complexity and little value, creates rigidity in a system, and often forces things to live in places they shouldn’t."
So encapsulation may not be as desirable in all contexts, possibly not even in most.
By taking the position that TS makes a functional style harder to practice compared to an object-oriented style. Just because it doesn't stop determined individuals doesn't weaken the claim. Typing OO code in TypeScript is fundamentally easier than typing functional code (which is also less awkward to type in a dedicated FP language). Given that JavaScript isn't statically typed it doesn't discriminate either way.
In a world with TypeScript but without JavaScript I doubt something like JavaScript Allongé would have ever been written.
TypeScript's priority was to type JavaScript's imperative aspects - so the later additions feel bolted on and awkward.
I didn't imply it was better. Some would say it is better because it eliminates inheritance, forcing the use of composition. The point is that there are different ways of practicing object-orientation - class-based is just one of them. JavaScript's OO was inspired by Self.
Why is it harder? You can still pass functions as arguments, return them from the other functions, and use popular algorithms like
map()
andfilter()
. And type safety helps you avoid making mistakes.Why is it a natural choice? Are we confusing here procedural programming and functional programming?
Thank you for your comment.
FP is harder, try to do typing for pipe, compose or curry. Trivial in JS hard in TS. Or try to represent polimorhic FP abstractions like functors. You can do it but you need to create typing for every Functor instance, you cannot easily do it without some HKT hacks available there. If you don't believe me check how look Ramda types declarations.
Yes you can fallback to unsound type like
any
but then we get type wholes and less compiler help.For the second, I don't think anybody today is considering using procedures (void functions), and not use a bit of functional or oop abstractions in the code. So no I didn't confuse anything.
With TypeScript 4 they alleviated the pain involved in typing e.g. ramda pipe a bit! They introduced variadic tuple types 🎉
Nice article, just wanted to talk about the private field declarations. They look so damn wierd to me for some reason. It is like seeing something that does something else on first instinct.
I think there is a larger problem with JS and OOP.
Javascript (and Typescript for that matter) was not built with OOP in mind making it difficult to do OOP properly. For example, OOP implies that you copy objects, which is rather difficult in JS, as you deal with references to other objects.
Kyle Sympson explains it better than I would ever do here : github.com/getify/You-Dont-Know-JS...
He also adresses the 'class' syntactic sugar here : github.com/getify/You-Dont-Know-JS...
but what about any
function
or JS literal is indeed an object? OOP is not about private, public, protected fields, or inheritance implemented with interfaces, abstract classes, or whatever.from a point of view your examples are OOP as well.
Yes they are. But the article is not about what means OOP, or about every element of it in JS, it's about the bit where the misconception came from
I think this article is a bit misleading then. There's nothing wrong with saying Typescript is OOP and there's nothing wrong with saying Typescript is FP, what it is really wrong from the quoted statement is:
«TypesScript is an Object oriented programming language whereas JavaScript is a scripting language»
This is not a false statement, this is a misconstrued statement. For starters what's a scripting paradigm? What kind of paradigm is that? OOP is a paradigm, not a language, Java is a language that implements OOP paradigm, C is a language that implements imperative paradigm. But none of them implement pure paradigms, for example it's not possible (or rather feasible) to implement OOP paradigm without imperative paradigm (look at C++) as much as it's not possible to introduce FP without OOP after more than 30 years of OOP programming.
Then the question is: is Javascript OOP? Yes it is implemented with prototyping. So again I think in my humble opinion the statement is wrong about Javascript, not about Typescript.
The statement is horrible. Both parts are wrong, as it's has vs form. This is OOP and this is not. Scripting is totally different thing than paradigm.
But to be clear it's only example. There are in the community all the time such opinions that TS is only for OOP, like you want OOP you don't use JS but TS. But truth is you want static type system you choose TS, it has nothing to do if you will do OOP or not.
The mainstream of developers sees OOP as classes and interfaces, as both ale in TS from beginning then TS is by many considered more OOP.
Fact is that OOP is not about only classes but about message passing, but I focused on the differences in class based OOP as this is always the main point.
Js is multi-paradigm and TS follows that.
First was typo, thanks for the comment. I meant exactly what you wrote, that it doesn't mean that TS has anything to C#.
Maybe they did, but the language has 8 years already and has changed and is changing. You cannot do comparison based on what was in the language before. I am talking about now, not 2012.
I am working with functional TS for more then three years already, I don't see any encourages from TS to force me to do OOP. I wrote classes in TS only because React was enforcing them before, no fault from TS side.
As I said in the article FP in TS is harder, agree, but it is out of point that TS is more object oriented, it is not. TS is constantly evolving and there are many concepts which will make FP simpler. But even now, you can write functional code in TS, if you say there is no for example HKT, ok Elm also doesn't have them, but its still purely functional language.
Try Nim lang for Functional Immutable OOP and better Types than Typescript and powerful Metaprogramming.
github.com/nim-lang/Nim/wiki/Nim-f...
Classes don't mean OOP. JS was OO before it had classes, using prototypes and constructor functions. But people didn't know how to use it as it was too different.
This article just continues building on misconceptions.
O agree with you that classes are not needed to do OOP. But this is how mainstream sees OOP, and unfortunately the same look at things have tc39 as they made them a way to the language.
Purpose of this article was not to describe what is or not OOP but decline any OOP differences between TS and JS
Great article! Hope many people get to read this.
The project that I'm currently working on is in TypeScript and it uses classes and functions alongside each other which works best for us. Using classes is a very good way to introduce dependency injection and make testability of complex components easier. But wherever possible we try to use simple pure functions.
Being extremely cautious with inheritance and try to avoid it in the majority of the cases.
I would love to read about using TS without classes and with fp approach. So far, even docs are pushing classes as the way to go and I'm reluctant to TS because of that.
We write many thousands of lines of TS code and, at least on the back end, we don't use the class keyword except in very rare cases where the class will be a singleton instance.
We don't go as far as using FP libraries and trying to do full FP, however we write all pure functions where possible, and use a few other really useful FP techniques to make code easy to write, test, and maintain.
We write OOP in the truest sense of the term, because we use objects and message passing, but we don't write anything like what most people consider OOP. The tight coupling with class inheritance is just terrible.
In any case, TS is not an OOP language. Most languages don't push you into a single paradigm and TS is no different.
I'm also not sure why people think FP is harder with TS than JS. There are generics which help with some of the problems I've seen listed.
Thanks for this comment. That is great. But about why it is harder, grab this code from Ramda
pipe
types:Like this type? Take them more here - Ramda types 😉
🤣
Its natural that docs of TS will also mention about classes as TS is multi-paradigm language and you can write OOP in the same way you can in JS. But there are also function typings, higher order functions support and so on, in official TS docs you have section how to type functions - handbook
JavaScript is an OOP language because it answers to the principles that define a language as OOP: d.umn.edu/~gshute/softeng/presenta...
Great Article !
ts is oop language though