Writing Components in Typescript

Package Setup 

Whether you are working on a TypeScript library or directly with a Wonderland Engine project, the setup will be the same.

You will need to install the typescript compiler using your favorite package manager (npm, yarn, etc…):

1npm i typescript --save-dev

Create a new configuration file called tsconfig.json at the root of your project/library:

1{
2  "compilerOptions": {
3    "target": "ES2022",
4    "module": "ES6",
5    "moduleResolution": "nodenext",
6    "experimentalDecorators": true
7  }
8}

Wonderland Engine uses modern JavaScript and TypeScript features, such as:

Some of those features require specific keys to be set in your configuration, such as:

  • “moduleResolution”: Allows to import from the API using the package “exports” field.
  • “experimentalDecorators”: Allows you to use decorators. See the Decorators section for more information.

For more information about the configuration, please have a look at the TypeScript documentation.

Editor Support 

The editor has first class support for Esbuild, a popular JavaScript and TypeScript bundler. Esbuild is able to directly transpile your .ts sources into .js files.

Before writing your first component, open Views > Project Settings. The panel will then appear on the right. Update the Project Settings > Scripting > entryPoint option from js/index.js to js/index.ts.

The setting you are looking for is highlighted here in red:

Writing Components in Typescript

You can now start writing your components using the .ts extensions.

Decorators 

With TypeScript, creating properties using the Property export leads to code repetition:

 1import {Component, Property} from '@wonderlandengine/api';
 2
 3class MyComponent extends MyComponent {
 4    static TypeName = 'my-component';
 5    static Properties = {
 6        myFloat: Property.float(1.0),
 7        myBool: Property.bool(true),
 8    };
 9
10    myFloat!: number;
11    myBool!: boolean;
12}

Each property must appear twice, once for the type declaration, and once for the definition. Decorators are here to help:

 1import {Component} from '@wonderlandengine/api';
 2/* Note the '.js' at the end of the import statement. */
 3import {property} from '@wonderlandengine/api/decorators.js';
 4
 5class MyComponent extends MyComponent {
 6    static TypeName = 'my-component';
 7
 8    @property.float(1.0)
 9    myFloat!: number;
10
11    @property.bool(true)
12    myBool!: boolean;
13}

Instead of using the non-null assertion operator in the class, you can also use dummy values:

1class MyComponent extends MyComponent {
2    static TypeName = 'my-component';
3
4    @property.float(1.0)
5    myFloat: number = 1.0;
6
7    @property.bool(true)
8    myBool: boolean = true;
9}

On the above example, note the missing ! when defining myFloat or myBool.