Vue.js + Old School TypeScript

Vue.js ist ja bekannterweise eines der großen MVVM-Frameworks im Web. Natürlich deutlich cooler als Angular. Zuletzt gab es für mich da einiges zu lernen, insbesondere wie man eine WPF+MVVM-Anwendung möglichst idiomatisch darauf portiert. Vielleicht dazu später mehr. An Vue gefällt mir sein leichtgewichtiger Ansatz, der sich in beliebige vorhandene Architekturen einbetten lässt und außerhalb von Vue nichts vorschreibt. Leider gibt es eine Schwachstelle: TypeScript!

Zwar wird Vue.js offiziell mit TypeScript unterstützt, wobei sicherlich die Verwendung von Class-Style Components am meisten Sinn macht. Aber hier gelten plötzlich einige Bedingungen. Man muss „modernes JavaScript“ nutzen, d.h. ohne Modulsystem und Type Loader kommt man hier nicht weiter. Nichts gegen modernes JavaScript und mit einem passenden Template für Webpack ist es auch schnell aufgesetzt, aber es gibt eben auch Bestandsarchitekturen und in meinem Fall wird TypeScript recht altmodisch mit Namespaces eingesetzt und ein Modulsystem gibt es nicht, stattdessen klassisches ASP.NET Bundling. Außerdem erfordert die standardmäßige TypeScript-Unterstützung Annotations, welche „experimental“ sind („Decorators are an experimental feature that may change in future releases.“, typescriptlang.org).

Wenn man diese Bedingungen nicht erfüllen kann oder will, dann bleibt nur der Verzicht auf TypeScript und die Verwendung der Vue-API ohne Typisierung:

declare var Vue: any;

Die Alternative vue4ts

Ich habe ein kleines Projekt aufgesetzt, welches ähnlich der Class-Style Components funktioniert, aber ohne Voraussetzungen genutzt werden kann: vue4ts

Die Library besteht aus nur einer Datei, die via Reference Tag inkludiert wird (wenn ein TypeScript-Projekt verwendet wird, ist das nicht nötig):

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

Die Vue-Anwendung erweitert die Klasse VueClass:

class MyApplication extends VueClass
{
  isAlert:boolean=false;
  testMessage:string=null;
  articles:Array<ArticleViewModel> =null;
}

Vue „Methods“ werden als, öhm, Methoden implementiert. „Computed“ Properties werden als Getter umgesetzt:

get articleCount()
{
  return this.articles == null ? 0 : this.articles.length;
}

doTest()
{
  this.testMessage = 'My test number is '+Math.random();
}

Auch die Lifecycle Events werden als ganz normale Methode implementiert:

mounted()
{
  this.$nextTick(()=> {
    alert('The component is mounted and rendered!')
  });
}

Components leiten anstatt direkt von VueClass von VueComponent ab:

class Box extends VueComponent
{
  article:ArticleViewModel=null;
}

Zuletzt müssen die Komponenten bzw. die Anwendung initialisiert werden:

Vue4Ts.component(new Box('box', document.getElementById('boxTemplate').innerHTML));

Vue4Ts.vue(new MyApplication(), '#container');

Dazu muss immer eine Instanz initialisiert werden, was sich bei Components nicht ideal anfühlt, aber zur Zeit eben nicht anders geht.

Alles andere ist Standardvorgehen bei Vue.

Wie funktioniert vue4ts?

Die Prototypen der Klassen werden analysiert, um daraus die ganz normale JavaScript-API von Vue zu „betanken“. Man beachte, dass die TypeScript-Basisklassen VueClass und VueComponent quasi nur Fake sind und zur Laufzeit überhaupt keine Rolle spielen. Stattdessen wird dem TypeScript zur Laufzeit die eigentliche Vue/Component-Instanz untergeschoben. Zum Glück setzt Vue hier den this-Kontext richtig.

Vermutlich funktionieren die standardmäßigen Class-Style Components auch nicht viel anders. Das Projekt ist auf Github nur sehr rudimentär angelegt. Ich werde die jeweils aktuelle Vue-API pflegen. Großartig Doku wird es nicht geben, zumindest von mir nicht. Aber vielleicht gibt es ja freundliche Unterstützer?