DEV Community

Cover image for No, TypeScript is not OOP version of JavaScript
Pragmatic Maciej
Pragmatic Maciej

Posted on • Edited on

No, TypeScript is not OOP version of JavaScript

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');
Enter fullscreen mode Exit fullscreen mode

The same part in TS

// TS🟦
class User {
    #name: string 
    constructor(name: string) {
        this.#name = name;
    }
}
const user = new User('Tom')
Enter fullscreen mode Exit fullscreen mode

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');
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

you can use type and intersection operator &

type X = Y & {x: number}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
macsikora profile image
Pragmatic Maciej

First was typo, thanks for the comment. I meant exactly what you wrote, that it doesn't mean that TS has anything to C#.

people think Typescript is for objective oriented javascript because that's how it was sold to a lot of people originally.

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.

The fact that Javascript has classes now doesn't negate the fact that Typescript encourages them more than plain javascript.

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.

If it's harder to do Functional Programming in Typescript

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.

Collapse
 
theau_poulat profile image
Big chicken

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...

Collapse
 
mikeborozdin profile image
Mike Borozdin

Is then functional programming harder in TS than in JS? Yes it is slightly

Why is it harder? You can still pass functions as arguments, return them from the other functions, and use popular algorithms like map() and filter(). And type safety helps you avoid making mistakes.

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.

Why is it a natural choice? Are we confusing here procedural programming and functional programming?

Collapse
 
macsikora profile image
Pragmatic Maciej

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.

Collapse
 
jopie64 profile image
Johan

With TypeScript 4 they alleviated the pain involved in typing e.g. ramda pipe a bit! They introduced variadic tuple types 🎉

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀 • Edited

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.

Collapse
 
nosyminotaur profile image
Harsh Pathak

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.

Collapse
 
cherif_b profile image
Cherif Bouchelaghem • Edited

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.

Collapse
 
gosukiwi_20 profile image
Federico Ramirez

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:

const obj = (function() {
  var private = 'hello';

  return {
    greet() {
      return private;
    }
  }
}());

obj.greet() // "hello"
obj.private // undefined
Collapse
 
cherif_b profile image
Cherif Bouchelaghem

Sure is doable like you said, but I have couple of concerns about your example:

What about when private is not initialized with hello 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

var state = new WeakMap();

/**
 * @class 
 */
class Todo {
    constructor(){
        state.set(this, {});
    }

    get name() {
        return state.get(this).name;
    }

    set name(name) {
        if (typeof name !== 'string') {
            throw('Todo name must be of string type');
        }

        state.get(this).name = name;
    }

    get description() {
        return state.get(this).description;
    }

    set description(description) {
        if (typeof description !== 'string') {
            throw('Todo description must be of string type');
        }
        state.get(this).description = description;
    }

    get status() {
        return state.get(this).status;
    }

    set status(status) {
        state.get(this).status = status;
    }

    markAsDone() {
        if (this.status === TodoStatus.DONE) {
            throw new Error('Todo is already done');
        }
        this.status = TodoStatus.DONE
    }

    reopen() {
        if (this.status === TodoStatus.OPEN) {
            throw new Error('Todo is already open');
        }
        this.status = TodoStatus.OPEN;
    }
}


module.exports = ({name, description}) => {
    const todo = new Todo();

    todo.name = name;
    todo.description = description;
    todo.status = TodoStatus.OPEN;

    return Object.freeze(todo);
};
Thread Thread
 
patroza profile image
Patrick Roza • Edited

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 like readonly 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.

Thread Thread
 
cherif_b profile image
Cherif Bouchelaghem • Edited

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:

delete obj.someProp;

I can freeze or use Object.defineProperty to achieve it, the later is more waste of effort.

I don't think that using WeakMaps has a big performance impact compared to closures.

Thread Thread
 
patroza profile image
Patrick Roza • Edited

I see, in TS trying to delete obj.someProp where someProp is marked readonly 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:

  • naming: e.g _myprivate, _MyClass_myprivate etc
  • documentation: e.g /** @private */
  • tooling support for said options (lint/doc/editor)

Editor support is of course very helpful, and in that, I think TypeScript as a supported standard is perhaps very helpful.

Thread Thread
 
cherif_b profile image
Cherif Bouchelaghem

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.

Collapse
 
perpetualwar profile image
Srđan Međo

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.

Collapse
 
macsikora profile image
Pragmatic Maciej

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

Collapse
 
jdforsythe profile image
Jeremy Forsythe

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.

Collapse
 
macsikora profile image
Pragmatic Maciej

Thanks for this comment. That is great. But about why it is harder, grab this code from Ramda pipe types:

export function pipe<T1>(fn0: () => T1): () => T1;
export function pipe<V0, T1>(fn0: (x0: V0) => T1): (x0: V0) => T1;
export function pipe<V0, V1, T1>(fn0: (x0: V0, x1: V1) => T1): (x0: V0, x1: V1) => T1;
export function pipe<V0, V1, V2, T1>(fn0: (x0: V0, x1: V1, x2: V2) => T1): (x0: V0, x1: V1, x2: V2) => T1;

export function pipe<T1, T2>(fn0: () => T1, fn1: (x: T1) => T2): () => T2;
export function pipe<V0, T1, T2>(fn0: (x0: V0) => T1, fn1: (x: T1) => T2): (x0: V0) => T2;
export function pipe<V0, V1, T1, T2>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2): (x0: V0, x1: V1) => T2;
export function pipe<V0, V1, V2, T1, T2>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2): (x0: V0, x1: V1, x2: V2) => T2;

export function pipe<T1, T2, T3>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3): () => T3;
export function pipe<V0, T1, T2, T3>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3): (x: V0) => T3;
export function pipe<V0, V1, T1, T2, T3>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3): (x0: V0, x1: V1) => T3;
export function pipe<V0, V1, V2, T1, T2, T3>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3): (x0: V0, x1: V1, x2: V2) => T3;

export function pipe<T1, T2, T3, T4>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4): () => T4;
export function pipe<V0, T1, T2, T3, T4>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4): (x: V0) => T4;
export function pipe<V0, V1, T1, T2, T3, T4>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4): (x0: V0, x1: V1) => T4;
export function pipe<V0, V1, V2, T1, T2, T3, T4>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4): (x0: V0, x1: V1, x2: V2) => T4;

export function pipe<T1, T2, T3, T4, T5>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5): () => T5;
export function pipe<V0, T1, T2, T3, T4, T5>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5): (x: V0) => T5;
export function pipe<V0, V1, T1, T2, T3, T4, T5>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5): (x0: V0, x1: V1) => T5;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5): (x0: V0, x1: V1, x2: V2) => T5;

export function pipe<T1, T2, T3, T4, T5, T6>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6): () => T6;
export function pipe<V0, T1, T2, T3, T4, T5, T6>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6): (x: V0) => T6;
export function pipe<V0, V1, T1, T2, T3, T4, T5, T6>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6): (x0: V0, x1: V1) => T6;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5, T6>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6): (x0: V0, x1: V1, x2: V2) => T6;

export function pipe<T1, T2, T3, T4, T5, T6, T7>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn: (x: T6) => T7): () => T7;
export function pipe<V0, T1, T2, T3, T4, T5, T6, T7>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn: (x: T6) => T7): (x: V0) => T7;
export function pipe<V0, V1, T1, T2, T3, T4, T5, T6, T7>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7): (x0: V0, x1: V1) => T7;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5, T6, T7>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7): (x0: V0, x1: V1, x2: V2) => T7;

export function pipe<T1, T2, T3, T4, T5, T6, T7, T8>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn: (x: T7) => T8): () => T8;
export function pipe<V0, T1, T2, T3, T4, T5, T6, T7, T8>(fn0: (x: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn: (x: T7) => T8): (x: V0) => T8;
export function pipe<V0, V1, T1, T2, T3, T4, T5, T6, T7, T8>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8): (x0: V0, x1: V1) => T8;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5, T6, T7, T8>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8): (x0: V0, x1: V1, x2: V2) => T8;

export function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9): () => T9;
export function pipe<V0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(fn0: (x0: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9): (x0: V0) => T9;
export function pipe<V0, V1, T1, T2, T3, T4, T5, T6, T7, T8, T9>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9): (x0: V0, x1: V1) => T9;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5, T6, T7, T8, T9>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9): (x0: V0, x1: V1, x2: V2) => T9;

export function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(fn0: () => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9, fn9: (x: T9) => T10): () => T10;
export function pipe<V0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(fn0: (x0: V0) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9, fn9: (x: T9) => T10): (x0: V0) => T10;
export function pipe<V0, V1, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(fn0: (x0: V0, x1: V1) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9, fn9: (x: T9) => T10): (x0: V0, x1: V1) => T10;
export function pipe<V0, V1, V2, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(fn0: (x0: V0, x1: V1, x2: V2) => T1, fn1: (x: T1) => T2, fn2: (x: T2) => T3, fn3: (x: T3) => T4, fn4: (x: T4) => T5, fn5: (x: T5) => T6, fn6: (x: T6) => T7, fn7: (x: T7) => T8, fn8: (x: T8) => T9, fn9: (x: T9) => T10): (x0: V0, x1: V1, x2: V2) => T10;
Enter fullscreen mode Exit fullscreen mode

Like this type? Take them more here - Ramda types 😉

Thread Thread
 
jdforsythe profile image
Jeremy Forsythe

🤣

Collapse
 
szabikr profile image
Szabi

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.

Collapse
 
juancarlospaco profile image
Juan Carlos

Try Nim lang for Functional Immutable OOP and better Types than Typescript and powerful Metaprogramming.
github.com/nim-lang/Nim/wiki/Nim-f...

Collapse
 
gosukiwi_20 profile image
Federico Ramirez

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.

Collapse
 
macsikora profile image
Pragmatic Maciej

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