DEV Community

Cover image for Back to the Front-end: Exploring the Future of the Umbraco UI (Part 7 - TypeScript)
Matt Brailsford
Matt Brailsford

Posted on • Updated on • Originally published at mattbrailsford.dev

Back to the Front-end: Exploring the Future of the Umbraco UI (Part 7 - TypeScript)

The next thing we'll be taking a look at is TypeScript.

This has been a bit of a divisive subject in Umbraco's history as the community have tried to get it into the core backoffice code base before, but given the nature of the codebase it was deemed too dificult. With a new codebase though, it really makes sense for it to be a first class citizen of the new UI and so it's really good to see it being adopted.

About TypeScript

In a nutshell TypeScript is JavaScript but strongly typed. What this means is that all variable/parameter types throughout your codebase will be explicitly defined and thus can be more easily checked for errors by developer tooling as you develop. This in turn reduces errors and makes for a more stable and predictable codebase.

TypeScript in and of itself though can't be run straight in the browser, it's really a middle layer to help with development. It must be compiled down to plain old JavaScript which can then be deployed within our application.

In our blog post series, this compilation is automatically taken care of for us by Vite.

The Basics

Explicit Types

Probably one of the most obvious things you'll notice when using TypeScript is how variables and parameters are often defined with an explicit type.

function greet(person: string, date: Date) {
  console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
Enter fullscreen mode Exit fullscreen mode

By providing these types our tooling can look for incorrect usages of our method and provide us with warnings that something is wrong.

greet("Matt", "2022-10-10");
// @err: Argument of type 'string' is not assignable to parameter of type 'Date'.
Enter fullscreen mode Exit fullscreen mode

We are then able to rectify the mistake before it even becomes an issue in our running application.

greet("Matt", new Date("2022-10-10"));
Enter fullscreen mode Exit fullscreen mode

If variables aren't defined with a type, TypeScript will attempt to infer the type from the assigned value and similalry warn if a future assignment is made that doesn't match that type.

let hello = "world";
hello = 42;
// @err: Type 'number' is not assignable to type 'string'.
Enter fullscreen mode Exit fullscreen mode

Static Type Checking

What makes it possible for TypeScript to warn us about problems in our code is that by providing strongly types information about our data, it is able to build up an internal memory of these types and then pre-emtively via our tooling warn us of any misuse before we even run our application.

const message = "hello!";
message();
// @err: This expression is not callable. Type 'String' has no call signatures.
Enter fullscreen mode Exit fullscreen mode

Without knowing these types, these checks could not be run and so the problems could only be found by running the application.

Non-exception Failures

Not only can we use TypeScript to validate our data types, we can also use it to look for code that is somewhat valid in JavaScript, but is often undesirable in practice, such as when accessing properties of an object that don't exist.

const user = {
  name: "Daniel",
  age: 26,
};

user.location;
// @err: Property 'location' does not exist on type '{ name: string; age: number; }'.
Enter fullscreen mode Exit fullscreen mode

Here TypeScript can provide us with a warning, where in traditional JavaScript user.location would simply return undefined.

Auto-completion

Because TypeScript is able to understand our codebase, another nice feature it provides us is type auto-completion.

TypeScript Autocompletion Example

Advanced Topics

Whilst this post is meant as a basic overview of TypeScript, there is one advanced topic that is worth mentioning as it's a key concept used in the backoffic UI code.

Decorators

Decorators are a special syntax that allows us to encapsulate some behaviour to be applied to a class, method, property or parameter at runtime. These are often used as syntactic sugar to simplify repeative tasks.

Whilst I won't go into how to make our own decorators, it's worth seeing them in action so we know what they look like.

A very common decorator used in the backoffice UI is that for defining a web component and it's exposed properties.

@customElement('message-box')
export class MessageBoxElement extends LitElement {

  @property({ type: string })
  public kind: string = "info";

  ...

}
Enter fullscreen mode Exit fullscreen mode

Whilst it is entirely possible as we saw in the Web Components post to register our component manually with the CustomElementRegistry, the customElement decorator enapsulates this behaviour for us and any class decorated with this expression will automatically be registered for us.

Similarly, we could expose our Web Components properties manually, with get and set functions that read and write the values to our elements attribtues collection, but by using the property decorator like this the implementation is taken care of for us.

NB: The customElement and property decorators used in this example are Lit specific decorators, but it's TypeScript that provides the mechanism for applying decorators.

Conclusion

TypeScript is very powerful and there is way more it can do than documented here, but what I've tried to do is just document the features you are likely to come across most day to day.

I'd highly recommend you take a look at the TypeScript docs for more on this subject, but I hope this gives you an intro to the subject.

One last thing to say on the subject is whilst you'll need to know TypeScript to be able to contribute to the new backoffice UI codebase, it is entirely optional when developing your own extensions so if you find it too much to deal with, then you don't need to use. Just note that most code examples you'll find from HQ and probably the community will use it so there will likely be some translation needed if you try to implement them in a codebase that isn't using TypeScript.

Personally I think it's a really worthwhile technology to get to grips with, especially for such a large application like Umbraco, but I think think it will also be really useful for package developers too.

Additional Resources

Top comments (0)