Blog

Latest news and updates from the PlayFab developers

by Joshua Strunk of Flying Car Games 2017-02-24

TypeScript: A PlayFab Customer Perspective

CloudScript is a great option for developers using PlayFab to create secure interactions on a player’s progression data, items, and more. CloudScript’s ease of setup and authoritative control does not come without its caveats. The CloudScript execution environment runs only pure JavaScript. JavaScript is a powerful programming language, but it can be daunting to learn for a developer new to dynamically typed scripting languages. Its complete lack of type safety can be a frequent source of headaches, along with its unusual prototype based inheritance system. Fortunately, JavaScript’s status as a web standard has resulted in a plethora of transpilers which target JavaScript.

For this guide, we will be leveraging the TypeScript transpiler to help reduce type related runtime errors and to allow the writing of more familiar inheritance-based object oriented code, when authoring code for CloudScript.

gif onHover documentation

gif IntelliSense/AutoComplete

TypeScript Overview

TypeScript is designed first and foremost to be a strict superset of JavaScript, with the added ability to layer on optional type information. This is great for developers needing to port existing code from JavaScript to TypeScript because valid JavaScript is valid TypeScript.

The feature which TypeScript gets its name from is its robust type system. TypeScript allows a developer to define types and interfaces in their code, which allows the TypeScript compiler to validate large parts of code ahead of runtime. This reduces the amount of time a developer spends running their game only to hit a CloudScript call which returns “JavaScript execution exception value x is not defined on object y”. With the added type information text editors and IDEs can offer far more helpful information than when working with plain JavaScript. Standard among editors that support TypeScript are IntelliSense, better code navigation (go to declaration, go to symbol, find all references, etc), and refactor support such as symbol renaming.

Another important TypeScript feature is the ability to use classes and inheritance in a more C++/C# style. Currently, vanilla JavaScript does not support the familiar structure of C++ style classes and inheritance. TypeScript, on the other hand, does have an object-oriented system like C++. Some might see this as a defect others will be thankful for the ability to fall back on a language structure they are familiar with.

Setting up TypeScript Development Environment

Some notes before diving into porting a CloudScript project to TypeScript. Like everything, in the JavaScript ecosystem, there is no one right way to setup a TypeScript toolchain. The method I’m presenting has been tried, tested, and refined over the past 6 months here at Flying Car Games.

Editor

For this guide, we will be using the Visual Studio Code text editor, because it is simple to setup, cross-platform, and has great TypeScript support built in. If you would like to use Visual Studio take a look at PlayFab’s CloudScriptTesting repository for an example VS project. If you would prefer to use another text editor both Atom and Sublime have excellent TypeScript plugins.

The TypeScript Compiler

The first step to using TypeScript is gaining access to the compiler. For this part, you will need to have node and npm installed on your computer. If you do not have node and npm you can find information on installing them here.

With node and npm installed you can install the TypeScript compiler by runningnpm install -g typescript

Once the compiler is installed start getting familiar with it by trying to compile small sample scripts. You can find a walkthrough of compiling sample code snippets in the TypeScript Quick Start guide. Once you feel confident with compiling examples through the command line, it is time to setup the Visual Studio Code task runner to run the TypeScript compiler to build your project. You can find a guide on how to do this on the VSCode website. I recommend testing the task runner with the small sample script you used to test compiling from the command line. If you are still not using a tsconfig.json file to define your compiler options, you should set one up and try it with the task runner.

Porting

Once you are comfortable with the TypeScript compiler, you can begin the process of converting your CloudScript project. Before diving into converting your *.js files to .ts files and getting the CloudScript TypeScript Definition files (.d.ts), first try and get all of your CloudScript’s .js files running through the TypeScript compiler and outputting to a single main.js file. You can tell the TypeScript compiler to output your compiled JavaScript to a single file by using the outFile compiler option. If you have the outDir compiler option set, in your tsconfig.json file, remove it. Inside the same tsconfig.json file add the outFile compiler option. “outFile”: “../distr/main.js”, for example. Try uploading the outFile to PlayFab to confirm your handlers are working as they did before.

With all your files compiling into a single out file its time to change all your file extensions from .js to .ts and grab the typings folder from PlayFab’s CloudScriptTesting repository. Now when compiling the project you should probably start seeing some type errors. Once you clean up the compiler errors and warnings your migration is complete. At this point, you can go back to working on your CloudScript code with the added type safety and Intellisense of the TypeScript compiler; however, I highly recommend starting to enhance your already written code with some basic TypeScript changes.

Enabling More Type Safety

  • Convert the declaration of your variables declarations from var to let. When using let to declare a variable name it becomes block scoped, var is not block scoped, if you have used any other programming language let behaves how you would have expected var to work.
  • Type your function parameters and return values. (This includes your args that get passed into your handlers, I find interfaces the easiest way to type these)
handlers.myHandler = function(args: IMyHandlerRequest) :IMyHandlerResponse {
    return {
        message: "CharacterId: " +args.characterId
    };
};
interface IMyHandlerRequest {
    characterId:string
}
interface IMyHanlderResponse {
    message:string
}
  • Start to type the key/values you parse from UserData, CharacterData,ItemData, etc..
interface IBaseUserInfo {
    dataFieldOne:string,
    dataFieldTwo:number
}
let userReadOnlyResponse = server.GetUserReadOnlyData({
    playerId: currentPlayerId
});
let userBaseInfo:IBaseUserInfo = JSON.parse(userReadOnlyResponse.Data["baseInfo"].Value);
userBaseInfo.dataFieldOne;
let numVar:number = userBaseInfo.dataFieldOne //Compile time error string not number
userBaseInfo.datafeildtow; //Compiler time error no property datafeildtow found on IBaseUserInfo
  • Just as you can type the key/values you parse from PlayFab you can type the key/values you are going to update, start doing it.
let userBaseInfo:IBaseUserInfo = {
    dataFieldOne: "string",
    dataFieldTwo: 1,
};
server.UpdateUserReadOnlyData({
    playerId:currentPlayerId,
    data: {
        baseInfo: JSON.stringify(userBaseInfo)
    }
});
  • When needing to type JS objects I tend to favor using interfaces over classes, your mileage may vary.