Introduction

TypeScript is JavaScript that scales. A language designed to implement complex use cases. It allows JavaScript to be written with types that are checked and removed at compile time. This resulting type safety allows for easier writing and maintenance of complex applications. This, among other things, is what has made TypeScript so popular: It allows finding bugs in code, especially on a large scale, much faster and easier than would be possible with pure JavaScript - and it works with JavaScript, not against it.

Deepkit is TypeScript that scales. A framework written in TypeScript for TypeScript, designed to develop very complex software in TypeScript. It brings many design patterns known from the Enterprise to TypeScript and introduces completely new features that are only possible with TypeScript’s new type system to increase development speed especially in teams. Small applications can also benefit from this new approach, as Deepkit comes with many libraries for very common use cases that can be used individually or in combination. The framework itself is designed to be as agile as possible and as complex as necessary, not only to get initial results quickly, but also to maintain development speed in the long term.

JavaScript is now the largest developer community in the world and provides the developer with a correspondingly large selection of many libraries and tools to cover the needs of a project. However, it is not always easy to find the right library. Often the philosophies, API and code qualities of these differ so much that a lot of sticky code and additional abstractions have to be introduced by the developer in order for these libraries to work properly with each other at all. The provision of core functions, which are needed by virtually every project, in nicely abstracted libraries brought together in a framework by a manufacturer or a community has proven itself again and again in the last decades: Java Spring, PHP Symfony/Laravel, and C++ QT are just a few very well-known and successful examples. These frameworks offer to the developer often far common and decades proven concepts, which are converted into libraries or components, in order to be able to be used so comfortably among themselves harmonizing demand-fairly. The offered functionalities and design patterns are thereby not cubed, but based on sometimes over decades old concepts, which worked satisfactorily by the fight in the competition with alternative ideas.

JavaScript has seen massive progress over the years, so that more and more design patterns from the enterprise environment can now be applied. Design patterns that can be found in more and more libraries, frameworks, and tools. However, JavaScript and also TypeScript have the problem that in order to efficiently apply many proven enterprise patterns, decisive functions are missing in the language itself. This does not mean that these design patterns cannot be applied in general, but that they are less efficient than in other current languages.

TypeScript completely removes its type information at compile time, once TypeScript is converted to JavaScript, so no information about it exists in the generated JavaScript or at runtime. It is undeniable that types are very valuable during development and when checking the correctness of the program. However, types also have tremendous value at runtime. This value is reflected where at runtime data is transformed (converted/serialized), data is validated, meta-information is added to objects, or interface information is required. In these and many other use cases, type information can be very useful at runtime because it provides libraries with the information needed to efficiently provide functionality. Currently, many of these use cases instead use alternatives that incompletely mimic TypeScript’s type system, forcing the developer to write types in a new way that has nothing to do with TypeScript’s syntax. The result is that TypeScript’s powerful type system can no longer show its strength here, and less ergonomic and less efficient ways of working must be used instead.

Deepkit Framework

Deepkit has developed a type compiler that leaves type information in place, allowing dynamic types to be computed at runtime and existing type information to be read at runtime. With this paradigm shift, completely new ways of working are possible, providing the required information for the aforementioned use cases, radically simplifying the development of complex software, and giving the code more expressiveness. It is thus possible for the first time to use the full power and expressiveness of TypeScript at runtime as well.

Based on this paradigm shift, Deepkit has developed a whole set of libraries for use cases that can be found in just about any program: Validation, Serialization, Database Abstraction, CLI parser, HTTP Router, RPC Framework, Logger, Template System, Event System and many more. The fundamental difference from other libraries is that type information is at the core of the functionality and as much TypeScript as possible should be reused at runtime, so less boilerplate needs to be written by the developer and even complex programs can be seen at a glance what they are doing. Finally, one of the key features of TypeScript is to give expression to even complex code, and Deepkit brings these expressiveness benefits to the runtime in the form of a powerful framework to now better scale application architecture with appropriate enterprise patterns.

Deepkit consists of two large areas: One is the Deepkit Libraries and the Deepkit Framework. The Deepkit Libraries are a whole family of standalone TypeScript libraries (NPM packages) that are good at one topic and are optimized, well tested, and designed to complement each other optimally. A project can use individual Deepkit libraries, or the entire Deepkit framework, which brings together all the capabilities of the libraries and complements them with additional tools such as the debugger. All together, it allows the developer to create complex, fast, and production-ready applications. Deepkit supports a wide range of use cases. From simple command-line tools (CLI programs) to web applications and micro-services to desktop or mobile applications. The code is designed to run in any known JavaScript engine (browser as well as NodeJS) and integrates beautifully with other frameworks such as Angular, React, and Vue. The claim behind Deepkit Framework is to apply clean code, SOLID principles, and enterprise design patterns to not only offer correspondingly high code quality, but to allow the user to apply them as well. Deepkit also tries to promote these same principles in its documentation and examples, but does not force the developer to follow them themselves.

High-Performance

One of the most difficult problems in software development is to maintain a high development speed even after months or years, especially when the code and the team grow. There are many frameworks that promise to get you started quickly and allow you to cobble together more complex applications on your own in a very short time. However, these usually have the common problem that the development speed decreases drastically the older the project or the larger the team becomes. It is not uncommon that even after a few months and only a handful of developers, the development speed collapses to such an extent that it drops to 1% of the original speed. To counteract this phenomenon, it is necessary to apply established design patterns and use the right framework and libraries in advance. Enterprise design patterns have established themselves for the reason that they scale excellently even with larger applications and large teams. Correctly applied, they develop their capabilities especially when a project is to be developed over a longer period of time (several months to years).

Design patterns have their advantages in theory, but in practice almost every pattern also has its disadvantages. These disadvantages vary depending on the language and framework, since the language and framework themselves determine how ergonomically a pattern can be applied. Just because a certain pattern can be used in a language, it does not mean that it automatically makes development better and faster. Some languages are better suited than others for applying certain patterns. With JavaScript or even TypeScript itself, various design patterns are often usable in the core, but there are limitations here that massively affect the user experience and thus speed. For example, Typescript decorators with all their idiosyncrasies may become necessary if a dependency injection framework specifies and is based on them. Deepkit’s runtime type system ensures that these design patterns can be applied in the most ergonomic way and with as little boilerplate as possible, unlocking their power to maintain high development speed not only initially, but also over the long term.

Isomorphic TypeScript

One of the biggest advantages of TypeScript is that complex code can be written better in many use cases. This includes frontend, backend, CLI tools, mobile and desktop apps, and much more. When a project spans these use cases and relies almost exclusively on TypeScript, it is called Isomorphic TypeScript. Using TypeScript in as much code as possible can massively increase development speed. So the following advantages are then suddenly available:

  • Code can be shared between departments (frontend, backend, microservice, etc).

    • Models, types and interfaces

    • Validation

    • Business logic

  • A unified audit system of a single package manager.

  • Reuse of known third-party libraries in all departments.

  • Knowledge sharing within teams.

  • Recruitment is simplified to one group (and the biggest one: JavaScript developers).

Deepkit framework and its runtime type system are designed to exploit these and more advantages of Isomorphic TypeScript to the utmost, so that its maximum powers are revealed.

Old approaches such as the dual stack (frontend and backend in different languages) can no longer keep up by far, since the context switch between the languages alone already costs an enormous amount of energy and time. All the other advantages that have already been explained even make it an unfair comparison. An isomorphic tech stack like TypeScript, properly applied, is many times faster in development time on a fundamental level than any combination of a dual stack for backend/frontend like Java/JavaScript, PHP/JavaScript, or even JavaScript/JavaScript. Since faster development speed also means less time needed for the same features, it also means that Isomorphic TypeScript saves cash. Besides all the advantages already presented, this is the killer argument to use Isomorphic TypeScript in all the next especially commercial projects.