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…):

npm i typescript --save-dev

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

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES6",
    "moduleResolution": "nodenext",
    "experimentalDecorators": true
  }
}

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:

Screenshot demonstrating how to change the entry point to a TypeScript source

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

Decorators 

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

import {Component, Property} from '@wonderlandengine/api';

class MyComponent extends MyComponent {
    static TypeName = 'my-component';
    static Properties = {
        myFloat: Property.float(1.0),
        myBool: Property.bool(true),
    };

    myFloat!: number;
    myBool!: boolean;
}

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

import {Component} from '@wonderlandengine/api';
/* Note the '.js' at the end of the import statement. */
import {property} from '@wonderlandengine/api/decorators.js';

class MyComponent extends MyComponent {
    static TypeName = 'my-component';

    @property.float(1.0)
    myFloat!: number;

    @property.bool(true)
    myBool!: boolean;
}

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

class MyComponent extends MyComponent {
    static TypeName = 'my-component';

    @property.float(1.0)
    myFloat: number = 1.0;

    @property.bool(true)
    myBool: boolean = true;
}

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