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.
Oldest comments (34)
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.
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...
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
anybut 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 🎉
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.
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.
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
privateis not initialized withhellovalue 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.
privateworks just fine to achieve exactly that and other modifiers likereadonlyetc.The only imo minor inconvenience of
privatecompared 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
freezeor useObject.definePropertyto achieve it, the later is more waste of effort.I don't think that using
WeakMaps has a big performance impact compared to closures.I see, in TS trying to
delete obj.somePropwheresomePropis markedreadonlywill 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_myprivateetc/** @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.
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.
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
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
pipetypes:Like this type? Take them more here - Ramda types 😉
🤣
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.
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