The beauty of TypeScript

The beauty of TypeScript

Introduction

Would you like to feel like a backend developer? Easy. First make a value object with at least 5 properties. Then make 5 variants of this objects with the same properties but slightly different names. Implement functions to transform between those objects (being frustrated doing that, I created Kotlin DTO generator), builder for those objects etc. If you do all that you should have at least a hundred lines of code, many classes and functions, you did a lot of work and implemented no logic yet.

I always thought it needs to be like that. Sure, I believe in separating layers of abstractions, and they should operate on different types, and so if we use staticly typed languages (that are surely best), there is no other option but to make many variants of the same objects and implement transformations over and over again. Then everything changed when I met TypeScript.

The new era

TypeScript offers much more powerful typing system than what we know from most staticly typed languages like Java, Kotlin, Swift, C++ etc. It is a powerful balance between what is static and what is dynamic. I see in it a great value both for frontend and for backend developers. Actually I believe (and hope) it is a beginning of a revolution that will start a new era of how we type programming languages.

Use cases

It is easy to show some small applications. What I am interested more is how we use it in standard and less standard use cases. Both for a frontend and for a backend. I am sure all programmers will easily recognize them from their experience.

I will compare TypeScript to Kotlin, which is much more concise than Java (thus take less space) and that is the second best typed language in my opinition ;) To make it clear, I don’t think TypeScript is better than Kotlin. I believe that for most uses TypeScript falls behind because of the JavaScript legacy. It misses many great functionalities that Kotlin has. I think that TypeScript has better typing system, that I would love to see in Kotlin as well.

Transformations between objects from different layers

As mentioned in the introduction, when we implement a clean architecture in our applications, in each layer we need to operate on slightly different objects (for instance Clean in Android, Hexagonal in backend). For instance, in the domain layer we might operate on an object Course when in endpoint definition we need to operate on CourseJson. This separation does makes sense, as we might want to change our domain object, and we should not be worried that we change our network definition as well (what would change our API and cause errors in all the clients). But as a result we need to make transformations between those objects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Course(
   val key: String, 
   val name: String, 
   val steps: List<Step>
)

class CourseJson(
   val key: String,
   val name: String,
   val steps: List<Step>
)

fun Course.toCourseJson() = CourseJson(
   key = key,
   name = name,
   steps = steps
)

fun CourseJson.toCourse() = Course(
   key = key,
   name = name,
   steps = steps
)

A great thing about TypeScript is that type is treated as a set of properties. If those properties do match, the type matches as well. A bit like the duck rule for types. So when objects are the same, transformation function are not even needed: // TO THINK: UserId is typed for a reason!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Course = {
    key: string,
    name: string,
    steps: Step[]
}

type CourseJson = {
    key: string,
    name: string,
    steps: StepJson[]
}

function courseToJson(course: Course): CourseJson {
  return course
}

function courseFromJson(courseJson: CourseJson): Course {
  return courseJson
}

But we do not define those types for fun. We do that do have flexibility to change one of them without influencing another. No problem at all. Say that we want our Json to have courseKey property instead of key. We also want to keep in the domain object some unexposed data in visibility property. In the transformation we need to copy the other object, and we set only what we need to change. // !! We would still expose visibility in such a case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type Course = {
    key: string,
    name: string,
    steps: Step[],
    visibility: string[]
}

type CourseJson = {
    courseKey: string,
    name: string,
    steps: StepJson[]
}

function courseToJson(course: Course): CourseJson {
  return {
    ...course,
    courseKey: course.key
  }
}

function courseFromJson(courseJson: CourseJson, visibility: string[]): Course {
  return {
    ...courseJson,
    key: courseJson.courseKey,
    visibility: visibility
  }
}

What do you think about the article?
Love
Super
OK
Confused
Dislike
Marcin
Marcin The author of the Effective Kotlin and Android Development in Kotlin books, founder of the Kt. Academy and Learning-Driven, programming trainer, speaker at international conferences, experienced developer.
comments powered by Disqus