Posts about TypeScript
In TypeScript, there is no way to pass a variable to a method by reference so that the method could both read its value and write a new value to it. For class fields, such functionality can be achieved to some extent by passing the field name to the method while still preserving type safety.
I have already written about union types in TypeScript in the past and explained how generic functions can be used with any underlying type and still preserve the original type as their return value. However, unless you're using the latest minor version of TypeScript (5.2 or later), this will not work for array operations on a common union type field.
Recently, I've been adding some GraphQL queries to a legacy web application in TypeScript. With GraphQL, you quickly end up with a lot of similar types, since the query determines which fields are present in a type. I was relying on the TypeScript compiler to warn me of resulting potential type incompatibilities, and was surprised when it quietly allowed a lambda with a subtype parameter.
In Ionic 6, component events have well-documented, strongly typed arguments. Unfortunately, the outputs in Angular are still typed as Event. The issue has already been reported and there is even a fix for it, but it did not make it into Ionic 6 as it would involve a breaking change. So until the fix is released, you'll have to settle for one of the workarounds.
Type checking in Angular is constantly improving. In newer versions, it even does a good job in templates. This can help us detect errors in our code earlier. However, sometimes extra work is needed to take full advantage of this feature.
The ng-template element in Angular allows you to reuse parts of a component template, which in a sense makes it a lightweight subcomponent. By default, its context is not typed, but it can be made strongly typed with a little trick.
If you want to share your Vue.js components across multiple projects, you would typically package them into a component library. However, the people behind the Bit platform propose that distributing each component as a separate package is a better approach. I decided to try implementing a basic solution for per-component packaging myself to see what it would take to get it working.
Although Vue CLI has built-in support for building component libraries, there's still some work in creating one, especially if you want it to be TypeScript and SSR compatible.
Storybook is a great tool for component development. But although it supports many frameworks, it still sometimes gives the appearance of being React-first. For example, the default configuration for Vue.js doesn't have TypeScript support.
Vuex store code can be quite verbose, especially with wrappers for type-safety in TypeScript. A lot of that plumbing can be avoided with the vuex-module-decoorators package. There's some extra configuration required to get it working in NuxtJS.
Even if you select TypeScript and Jest support when creating a new NuxtJS project, it still isn't fully configured for writing tests in TypeScript, let alone for testing components written with JSX syntax. This post describes my journey to a working configuration.
Although both Vue.js and NuxtJS have TypeScript support, it often seems incomplete. For example, there's no compile-time type checking in Vue.js templates. Any errors will only be reported at runtime. Currently, the only way to achieve compile-time type safety is to use render functions with JSX syntax instead.
String literal types are a lightweight alternative to string enums. With the introduction of the const assertions in TypeScript 3.4, even type guards can be implemented in a DRY manner.
I've been doing some Cordova plugin development recently and at some point, I've decided to add TypeScript type declarations to make the plugin easier to consume from Ionic (or other TypeScript based) applications.
I have a hard time recommending the book to anyone. Although it mostly focuses on basics, I don't think it's suitable for beginners because of how short the explanations are. For me, its value was mostly in a few random nuggets of knowledge I stumbled upon while reading.
Recently, we discussed the behavior of Promise.finally in our development team. Even after reading the official documentation, we weren't unanimous on what will happen in certain cases. In the end, I wrote a couple of test cases to make sure about it.
In Ionic 4, even for lazy-loaded modal pages the component must be specified using the type. There's nothing wrong with that. Enforcing strong typing is usually a good idea. However, it can potentially cause a circular dependency, especially if you move the code for creating and opening modal pages to a separate service to avoid repeating the same boilerplate code and make testing easier.
RxJS used to encourage monkey patching of operators and helper functions onto the Observable object. However, this has an unfortunate side effect of making the imports available everywhere. Removing an import from one file can inadvertently break code in other files. To alleviate this problem, alternative imports in the form of lettable operators are available since RxJS 5.5.
Ionic Native makes it very convenient to use Cordova plugins from Ionic applications. Although Ionic Native provides an impressive collection of wrappers for many Cordova plugins, there are still Cordova plugins out there without a corresponding plugin. In such cases you will need to either use them directly without a wrapper or write your own wrapper. The latter option is much simpler than you might think.
The biggest advantage of having a formal description for a RESTful API is the ability to programmatically generate client-side code for calling the service. Unfortunately, it turned out that Swagger tooling still leaves much to be desired, at least for generating TypeScript Angular code.
I keep getting impressed by how feature-rich dependency injection in Angular is. This time I needed it to inject the appropriate implementation of a dependency based on runtime information. Of course, the scenario is well supported.
Angular has great support for validating data in forms, both template-driven and and reactive ones, built imperatively with FormGroup. It is also easy to create own custom validators. However, I did not find it obvious, how to use injected dependencies in non-directive validators for reactive forms.
Many Angular 2 and Ionic 2 APIs return RxJS observables. To unit test your code that's consuming them, you will need to create your own observable streams with test data. With this approach I wrote tests for code reacting to user's current geolocation.
Angular makes heavy use of ECMAScript 2015 modules. All components and other Angular objects are modules themselves, therefore the tutorials explain early on, how to import and use them. However, how does one import a third party library which still exports legacy CommonJS or AMD modules?
By default, Ionic 2 produces unminified development builds. To force an optimized production build, you need to add --prod switch to ionic build or ionic run command. Since development build doesn't include Angular AoT (Ahead of Time) compilation, your production build might turn out broken even if development build of the application worked just fine.
In version 2.1 that was released in December 2016, TypeScript finally added support for downlevel transpilation of async and await keywords for ES3 and ES5 targets. To give this new feature a try, I decided to convert the Angular Tour of Heroes tutorial to use async and await.
Having unit tests usually drastically reduces the need for interactive debugging. However, being able to debug unit tests can sometimes prove very useful. Nowadays, any browser includes a fully featured debugger as part of its developer tools, and Karma test runner has a dedicated feature for in-browser debugging. I wrote short instructions on how exactly to use this feature for a project I am working on.
Although, I have now configured my Cordova project to automatically copy distribution files from installed Bower packages and reference them from HTML pages, there's still one final part of Bower-related configuration left: unit tests also require Bower dependencies. I don't want to manually update the configuration of my test runner every time I install an additional Bower package.
I have no reservations about recommending the book to any existing or future TypeScript developer. It can serve as the first book to start learning the language, but can teach you a lot even if you have already been programming in it for a while.