Allen Conway's Blog

Exploring all things software engineering and beyond...

How to Prevent Visual Studio from Compiling TypeScript

If you are building a Single Page Application / JavaScript Web application using Visual Studio, you've probably already run into the overlap between tooling that surrounds npm and the tooling within Visual Studio. As web development moves further away from the bells and whistles needed from the IDE (unlike heavy server-side web technologies like ASP.NET MVC that are heavily dependent upon the IDE), separating a project from these 'features' can be not quite straight forward. While the practice of using Visual Studio for modern web development isn't as prevalent these days with much of the coding taking place in streamlined IDEs like Visual Studio Code, there are still a lot of projects that exist and have a hard time decoupling from Visual Studio, MSBuild, and ASP.NET because of their coupled nature. This process will help in this interim stage while the code is still fully integrated and run from Visual Studio.


One of these tasks is preventing Visual Studio from being responsible for building TypeScript and allowing your tooling (i.e. Webpack, Gulp, Grunt) to be in charge instead. The idea here is that your tooling has been configured to lint, minify, build, concat, bundle, copy, whatever all of your project files exactly as you desire. At this point you don't really need MSBuild involved in transpiling your JavaScript to TypeScript as it would be redundant and often times problematic. To prevent Visual Studio from doing any compilation of TypeScript preform the following steps:

1. Ensure a tsconfig file is added to the project and configured correctly

TypeScript and any build process you are using will work together based on the configuration in tsconfig.json. This file can be hand-rolled from scratch, or may have been generated for your project from a process like ng new and the Angular CLI. You can also generate a default tsconfig file (recommended approach as opposed to creating from scratch) using the following command:

tsc --init

This will generate a default configuration file for TypeScript compilation. Your web-client's code build process will need to point to this file and using it as a driver for the TypeScript compilation behavior.

2. Modify the .csproj project file to prevent TypeScript from compiling

Within Visual Studio, right-click your project and select the option to edit the .csproj file. These options are in a XML format and the following needs to be added:

<PropertyGroup>
   <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup>

If you still want MSBuild to handle your TypeScript compilation there are several options that will change the behavior: 


One of the only primary use cases I can think allowing MSBuild to handle TypeScript compilation is for using TypeScript independently of a framework/app like Angular or React when using standalone in an ASP.NET MVC application. Otherwise the native build processes of your front-end stack are much better off being used to build TypeScript as opposed to MSBuild.

State of the Union: Future and Historic Thoughts on WebAssembly, JavaScript, and .NET

With all the goodness happening in the world of WebAssembly it's important to keep an eye on what's happening and how this will positively impact development going forward. In the world of JavaScript there are questions about how the worlds will converge. This maybe in contrast with a portion of the .NET community, which seems at times they don't want it to converge; they want JS dev to be thrown out with the garbage as evidence by the sly remarks toward our community over the years (which as a JS dev I've digested kindly). This sentiment is also supported via the primary description of Blazor:

Blazor lets you build interactive web UIs using C# instead of JavaScript

Although that picture gets clearer as I realize their baby (web in .NET) was called ugly for the last decade so they are salivating for Blazor to feel at home again on the web. (zing!) OK back on track and in all seriousness, Blazor is a rich platform to build modern apps using C#, and I do fully appreciate the excitement of being able to run the same code on the client and server. This is a significant strength in addition to several other bullet points about the stack. 

BTW, I qualify to make these remarks as I've been both a .NET developer and a JavaScript developer, so I've been on both sides of the fence for extended periods of time. Just look at the header image on this blog; it's a legacy Visual Studio logo representing the numerous years I've spent as a .NET developer.

History will show though without JS, the development community as a whole I don't think would be near where they are today and still creating per-platform apps like 15 years ago. The ability to write-once and deploy platform agnostic for the last 10 years is unparalleled until recent advancements. It's historic significance can't be ignored. 

Also there is no hidden agenda here to resist change or remain some kind of isolated JS developer wearing blinders. I'm not that dogmatic in my career path as I've typically moved along with change remaining modern to where mainstream development has gone, and not tried to hang on to a stack out of stubbornness. I'll adopt change as the community does, and always excited about the advancements of the future.

The reality is there is too much momentum in JavaScript development for companies/customers/clients to pump the brakes and change everything. This process is always an evolution. There is also the fact that not all development is greenfield, so the question arises about how to have the best of both worlds (JS and WASM)? 

Being pragmatic and assessing the current landscape, I think the real step forward for folks not purely on a single stack like C#/.NET, or any narrow/single stack for that matter will be a hybrid one (by definition hybrid); at least in the beginning. This is even suggested straight from the horse's mouth: https://webassembly.org/docs/faq/


I feel like bullet points 2 and 3 above will emerge in the 1st 3-5 years as a prevalent way of developing modern web apps. A hybrid approach that uses both JavaScript and compiled WASM modules referenced within to produce performant and modern web applications. The language used to create and target a WASM module will be dependent on the team's experience. 

Here are some interesting examples that do just this:

Angular:

React:

It's important to continually modernize our stack and remain fluid with the direction the community guides us. WebAssembly plays an important role in the future of all types of development. What are your thoughts on how this will evolve?

Using Quokka.js for Real-Time Feedback in TypeScript

I'm always looking for cool VS Code extensions and Quokka.js certainly hits the spot. It provides real-time feedback on JavaScript and TypeScript directly in VS Code in a variety of forms. For example if you're testing some code via console.log, you can get the output directly inline to the right of the code which is awesome.

Once installed, all I needed to do was open the command pallet in VS Code (Ctrl+Shift+P) and select, 'Quokka.js: Start on Current File' as shown below:


After initiating the extension, as seen below I was getting live logging directly in the code.


If there's a value not provided in the scope of the file, Quokka.js obviously can't produce an output and this was expected behavior:


There is quite a bit more functionality offered like code coverage assessment (as it pertains to code execution paths, not unit testing), and a provided value explorer. There is also a Pro edition with additional tools available.

Check out the links below to get started:

Quokka.js
VS Code Extension for Quokka.js

I'm excited about WebAssembly, but not as much about my beloved .NET, Blazor's implementation

As a web client developer these days, I'm sold on WebAssembly and looking forward to it's adoption by the multiple languages that can compile to it. However interestingly one of the things I'm beginning to feel is my personal dislike for the Blazor syntax and implementation. I suppose my multiple years being entrenched in JS/TS with really enjoying TypeScript + the SPA frameworks that have a relatively clean separation of markup (declarative) and logic (imperative) has made me have a bit of dislike for lacing the view directly with imperative view logic like this in Blazor:

@page "/myorders"
@inject HttpClient HttpClient

<div class="main">
</div>

@if (ordersWithStatus == null)
{
  <text>Loading...</text>
}
else if (ordersWithStatus.Count == 0)
{
  <h2>No orders placed</h2>
  <a class="btn btn-success" 
        href="https://www.blogger.com/2404">Order some pizza</a>
}
else
{
  <text>TODO: show orders</text>
}

As a side of humor, to format code blocks on this blog I have to select a 'brush' for the language formatting. Case in point, in the above snippet I wasn't sure if I should have picked HTML, C#, or Blazor.

This is probably because I was never a fan of the classic ASP, MVC Razor, or even Blazor implementations where view logic is interlaced with the markup (for web client code I'd even throw in JSX - as explained here). This doesn't matter a pile of beans really because this is all subjective and has absolutely no bearing on how successful Blazor or any other language targeting WebAssembly will be. I actually love the .NET stack and was carved from that block since the beginnings of my professional career, but I just don't like that particular style of implementation for the web. Shoot for all of ASP.NET's webforms shortcomings, the view overall was relatively clean (keeping logic in code separate from the markup) and pure aside the fact the tags may have been ASP.NET server-side controls but still took the shape of HTML tags (analogous in form to today's custom HTML elements).

I also do not like the JSInterop style in Blazor. You can invoke JavaScript functions from within C#, and that alone is handy I suppose, but messy. The functions you want to invoke must be available on the global scope of windowYuck. JavaScript scope and encapsulation was difficult enough to manage through the years, I'd rather not go back to the days of hanging code off the window object making everything globally available. In 100 level examples this seems fine, but get to 10's or 100's of thousands of lines of code in an enterprise app and this could get ugly.

<script>
  window.MyFunction = (someValue) => {
    //JS code here...
  };
</script>

using Microsoft.JSInterop;
public class JsInteropExample
{
  public static Task MethodName(strings someValue)
  {
    return JSRuntime.Current.InvokeAsync("MyFunction", someValue);
  }
}

I'm probably not alone in my opinions, and that's why I'll be keeping an eye on the ability to use TypeScript as a target for WA. I like JS/TS and am comfortable with it for developing web applications. I feel many client side developers may have a similar sentiment and not want to either learn a server-side language, or just prefer the front-end languages they've been using for years. TS on it's own won't be enough (it's just a language), so it would have to be TS + some web framework (??) and we'll have to wait for the pieces to come together.

To that end I'll keep an eye on things like assemblyscript which is a TypeScript to WebAssembly compiler. It doesn't appear to have the traction some of the other compilers do at the moment, but I'm sure it or something similar will gain momentum as WA picks up and the masses of web developers may not feel like using C#, C++, or Rust.

AssemblyScript: a TypeScript to WebAssembly compiler

AssemblyScript: Status and Roadmap

I'm not counting Blazor out for sure, and it's still going to evolve as it's only an experimental project at the moment. I really enjoy developing in C# so it seems like a great match, but in it's early stages it's rough around the edges and maybe that's just my opinion that's shaped as a front-end developer. I'm pragmatic and will not count out the usefulness of developing on a single-stack and this is where Blazor shines for .NET developers. 

I'd be interested in feedback or thoughts about using TypeScript to transpile to WebAssembly or anything else along these lines, so please feel free to leave a comment and let me know.

Named vs Fat Arrow Functions in TypeScript

When working with TypeScript, it's important to understand some of the key differences between named and fat arrow functions. Let's have a look at a basic class with one of each type of function defined, and also the resulting ES5 that TypeScript transpiles to for a better understanding.

Here is a sample TypeScript class with the two different types of functions.

class MyTsClass {

    private myValue: number = 0;

    myNamedFunction(): void {
        setTimeout(function () {
            console.log(`Inside myNamedFunction, this.myValue = ${this.myValue}`);
        }, 1000);
    }

    myFatArrowFunction = (someValue: number) => {
        this.myValue = someValue;
        console.log(`Inside myFatArrowFunction, this.myValue = ${this.myValue}`);
    }
}

const myClass = new MyTsClass();          
myClass.myFatArrowFunction(1);
myClass.myNamedFunction();

Here is the resulting transpiled ES5 JavaScript.

"use strict";
var MyTsClass = /** @class */ (function () {
    function MyTsClass() {
        var _this = this;
        this.myValue = 0;
        this.myFatArrowFunction = function (someValue) {
            _this.myValue = someValue;
            console.log("Inside myFatArrowFunction, this.myValue = " + _this.myValue);
        };
    }
    MyTsClass.prototype.myNamedFunction = function () {
        var _this = this;
        setTimeout(function () {
            console.log("Inside myNamedFunction, this.myValue = " + _this.myValue);
        }, 1000);
    };
    return MyTsClass;
}());
var myClass = new MyTsClass();
myClass.myFatArrowFunction(1);
myClass.myNamedFunction();

For the purpose of this post, we'll concentrate on (2) main aspects of the code
  1. Where the method is created on the object, and the resulting performance impact
  2. How the this keyword behaves
It's important to understand the differences because there is a performance impact. Notice how the named function on the class is created and attached on the object's prototype. In this manner, the method is stored in memory only one time, as objects created from the same constructor point to a single prototype object. This is the more memory efficient implementation.

Now inspect the fat arrow's function in the ES5 code. Because the method is declared and created in the object's constructor (instance member), it will be declared again per each new instance of this type of object created. This has a memory and performance overhead. As a note, this is the identical resulting behavior to explicitly creating methods within the class constructor in TypeScript.

At this point we might be thinking, "Well that's enough let's just use named functions which will be declared on the object's prototype and be done with it!" There is more than meets the eye and the fat arrow function is quite useful. One of the main advantages is that fat arrow functions lexically capture the context of this in TypeScript. This is critically important in functions that contain callbacks or where re-assignment of instance variables might occur. The former use case is one that we run into often with observable callbacks in say Angular components. You may have run into issues with the this keyword and noticed it wasn't the correct context. The issue is if not using the fat arrow syntax, the context of the this keyword will be undefined. If strict mode isn't enabled, the context of this will be of the window object. If you look in the ES5 tanspiled code, you'll notice this is captured from outside the function body allowing our context to be captured correctly.

var _this = this;

Let's look at the console output from the original code above. Notice in the setTimeout call the use of this. However in this instance it's not the proper context resulting in undefined when accessed. 


The fix is to update the callback to use the fat arrow syntax which will capture the correct context of this

myNamedFunction(): void {
  setTimeout(() => {
    console.log(`Inside myNamedFunction, this.myValue = ${this.myValue}`);
  }, 1000);
}

If we run the code again, we get the console output we expect.


In a TypeScript project with the default configuration of "noImplicitThis": true set in the tsconfig.json file, you'll actually be warned in the IDE of this scenario, " 'this' implicitly has type 'any' because it does not have a type annotation." This would be an indication you need to use the fat arrow function instead.


There are other use cases beyond the ones I'm mentioning here today in regards to the behavior of this with inheritance and calling the parent class as well as other differences. However these are two key areas that should be understood, as I see the usage flip-flop without intent, and developers should be aware of the performance and behavior differences and create the correct type where appropriate. They have separate purposes, so I'm not a fan of just one or the other. Using only fat arrow functions have their performance impact, but shouldn't be avoided all together as they are instrumental on capturing the correct context of this when needed. 

Visual Studio Code Snippet - Triple Slash Directive

Sticking with the theme of my last blog post, Running ES6 Modules Native in the Browser using TypeScript, this post looks at pure JavaScript/TypeScript projects (i.e. NodeJS), that might not be using a framework or module loader, yet still need the ability to reference dependencies from other files. We've been doing this for years using the Triple-Slash Directive like the following:

/// <reference path="./src/ts/myClass.ts" />

In Visual Studio Code I was looking for an extension, snippet, or shortcut to type out the above. Interestingly I came up with nothing. Maybe it's inside another extension I hadn't seen, but rather than look for a needle in a haystack, I decided to quickly hand-roll my own snippet. This is trivial to do in Visual Studio Code. Here is the snippet for a triple-slash directive, and it can be used with the following prefix name: "tripSlash"

{
  "Triple_Slash_Directive": {
      "prefix": "tripSlash",
      "scope": "javascript,typescript",
      "body": [
        "/// <reference path=\"${1:path}\" />",
      ],
      "description": "Triple Slash Directive used for declaring dependencies between files when no module loader is used"
  }
}

Running ES6 Modules Native in the Browser using TypeScript

ES6 Modules have a clean and intuitive syntax, and it's nice to know that there is now widespread support natively to use them in the browser. The main drawback to date is that not every browser version dating back supports ES6 modules and thus a module/loader bundler is still required for production applications (only one of many reasons). However it can be a lot of work to spin up Webpack or SystemJS just to throw together a small test application. Another use case might be if building an intranet app in a controlled/known environment using a supported browser. Regardless of the reason here is how you can use ES6 modules natively in the browser using TypeScript or JavaScript. (This post will focus on TypeScript, but you can use plain JS too)

1. Create an ES6 module

A module is nothing more than a self-contained set of functionality, executed within their own scope and not on the global scope. We'll use the export keyword to expose that functionality outside the module, and the import keyword to use that exposed functionality in another module.

export class Person {
    getAddress():string{
        return '123 Pine St.';
    }
}


2. Create another ES6 module importing the module created previously

import { Person } from "./Person.js";
export class ContactInfo{
    getContactInfo() {
        const person = new Person();
        const address = person.getAddress();
        console.log(`The address is: ${address}`)
    }
}

Make sure to note that "bare" modules are not supported. This restriction allows for browsers to scale in the future when using module loaders, and allow "bare" modules to contain special meaning or functionality. This syntax below is not supported and you'll get the following error in the browser, even though the application might build correctly:

import { Person } from "Person";
"Uncaught TypeError: Failed to resolve module specifier "Person". Relative references must start with either "/", "./", or "../"."

The correct syntax is to reference the exact file directly. 


3. Configure tsconfig.json

Configure the module type to be "ES6." Using anything else will ultimately yield in errors in the browser at runtime as the other module types are not supported. 

"compilerOptions": {
    "module": "es6"
  }


4. Leverage the "module" type in index.html

As this isn't a classic script, we must identify the file as being a module using the type="module" attribute. Note you can use the async attribute with modules if desired which will execute the script as soon as possible, without a guarantee of order, and also not waiting for the HTML parsing to finish. There is also no need to add the defer attribute as it behaves like this by default; a module script can't block the parser.

<script src="scripts/typescript/Person.js" type="module"></script>
<script src="scripts/typescript/ContactInfo.js" type="module"></script>


5. Run and check for errors

If you see any errors such as "exports is not defined" or "define is not defined" then you probably have the tsconfig.json configured incorrectly and it's instead transpiling to another module type that is unsupported in the browser (i.e. commonjs, amd, etc..) natively without a module loader. If testing the basic functionality above, upon calling getContactInfo() you should see the output in the debugger.


For a full list of browser compatibility on ES6 module support, see the following link:
JavaScript modules via script tag

If you're wondering about the .mjs module file extension support in TypeScript, see the following discussion on GitHub: Support '.mjs' output