Why Typescript?
about me… Jeff Francis
you
So what is TypeScript?
a typed superset of JavaScript
a typed superset of JavaScript
it’s JavaScript… but built for more scale
coffeescript Dart Coco LiveScript IcedCoffeeScript Parsec Contracts.coffee Uberscript ToffeeScript Caffeine heap.coffee EmberScript Jack move Moescript pogoscript LispyScript wisp Hot Sibilant ki jisp Ham GorillaScript RedScript Daonode LiteScript ColaScript Taijilang MoonScript Earl Khepri Spider CirruScript Pallet TLC CokeScript imba TeJaS asm.js JavaScript++ MileScript Mascara Roy Elm JSX Este.js Swym Typecast.js PureScript AtScript Flow Streamline.js mobl StratifiedJS NarrativeJS jwacs Wind.js TameJS Continuation.js Kal JSPipe promiseLand ContextJS Objective-J Mochiscript jangaroo Flapjax jLang Restrict TIScript Six js-- Latte JSX Ruby Python Erlang Perl Java/JVM Scala C# F# Lisp Scheme ClojureScript Ocamljs Haskell Smalltalk C/C++ Basic Pascal Go SQL PHP. etc… source: https://github.com/jashkenas/coffeescript/wiki/List-of-languages-that-compile-to-JS
OK, so what does TypeScript do to add scale?
1. prevents trivial errors 2. makes code more readable 3. discovers the impact of change
1. prevents trivial errors 2. makes code more readable 3. discovers the impact of change
types find simple bugs
var message = "The inning is: " + inning;
var inning = { label: "Fith", count: 5 } var message = "The inning is: " + inning;
your code already has types
var isBatting = false; var inning = 6; var teamName = "Blue Jays"; var runsRecord = [1, 6, 3];
var isBatting: boolean = false; var inning: number = 6; var teamName: string = "Blue Jays"; var runsRecord: number[] = [1, 6, 3];
JS types are just pretending to be any type
var isBatting: any = false; var inning: any = 6; var teamName: any = "Blue Jays"; var runsRecord: any[] = [1, 6, 3];
var isBatting: boolean = <any> false; var inning: number = <any> false; var teamName: string = <any> false; var runsRecord: number[] = <any> false;
var pitch = function(type) { if (type == "fastball") return 170.5; else return 123.9; };
var pitch = function(type: string): number { if (type == "fastball") return 170.5; else return 123.9; };
var pitch = function(type: string): boolean { if (type == "fastball") return true; else return false; }; var x = pitch("curve"); console.log(x – 10); --error
implicit conversions are evil
(0 == []) == true (!!0 == !![]) == false 0 + [] == "0" ???
this
... this.catch().then(function(ball) { this.throw(ball); });
var _this = this; this.catch().then(function(ball) { _this.throw(ball); });
... this.catch().then((ball) => { this.throw(ball); });
prototypes to classes
var Player = function(jerseyName, fielding) { this.jerseyName = jerseyName; this.currentPosition = fielding; } Player.prototype.throw = function() { console.log("Throwing"); } var jeffFrancis = new Player("FRANCIS", "P");
class Player { jerseyName: string; currentPosition: string; constructor(jerseyName: string, fielding: string) { this.jerseyName = jerseyName; this.currentPosition = fielding; } throw(ball) { console.log("throwing"); } } var jeffFrancis = new Player("FRANCIS", "P");
class Player extends Person { jerseyName: string; currentPosition: string; constructor(jerseyName: string, fielding: string) { super(); this.jerseyName = jerseyName; this.currentPosition = fielding; } throw(ball) { console.log("throwing"); } } var jeffFrancis = new Player("FRANCIS", "P");
var
var player = oldPlayer; for (var i = 0; i < trades.length; i++) { var player = trades[i]; trade(player); } expect(player).toBe(trades[trades.length -1]);
var player = oldPlayer; for (var i = 0; i < trades.length; i++) { let player = trades[i]; trade(player); } expect(player).toBe(oldPlayer);
for (var i = 0; i < trades.length; i++) { player = trades[i]; trade(player); }
var LINEUP_SIZE = 9; LINEUP_SIZE = 10;
const LINEUP_SIZE = 9; LINEUP_SIZE = 10; … error
1. prevents trivial errors 2. makes code more readable 3. discovers the impact of change
types add reader context
function placePlayer(player, role) { PlayerManager.add(player, role); } … placePlayer("FRANCIS", "P"); placePlayer(new Player("FRANCIS"), 1); placePlayer({ name: "Francis" }, 1);
enum Fielding { B1, B2, B3, SS, C, LF, CF, RF, P}; function placePlayer(player: string, role: Fielding) { PlayerManager.add(player, role); } … placePlayer("FRANCIS", Fielding.P);
typed JSDoc isn’t as good as actual types /* @param {!Array.<!number>} mn Incoming tanget of last point. */
… var players = $(selected)
$(selector) $(element) $(element array) $(html) $(callback) $($)
building with modules is now easier
<script src="baseball.js"></script>
document.createElement("script")
most must compile…
if (!namespace) namespace = {}
module Baseball { class Player { jerseyName: string; currentPosition: string; constructor(jerseyName: string, fielding: string) { this.jerseyName = jerseyName; this.currentPosition = fielding; } throw(ball) { console.log("throwing"); } } }
import Person = require("Person"); module Baseball { class Player extends Person { jerseyName: string; currentPosition: string; constructor(jerseyName: string, fielding: string) { super(); this.jerseyName = jerseyName; this.currentPosition = fielding; } throw(ball) { console.log("throwing"); } } } export = Baseball;
let and const also help with readability
it is easier to read when you can play with the code
but...
File file = new File("some_file.txt"); BufferedReader reader = new BufferedReader(new FileReader(file)); String line = reader.readLine(); while (line != null) { System.out.println(line.toUpperCase()); line = reader.readLine(); } reader.close(); File.open("some_file.txt") do |file| file.readlines.each do |line| puts line.upcase end end
import java.util.Comparator; public class PlayerComparator implements Comparator { @Override public int compare(Player p1, Player p2) { String name1 = p1.getName(); String name2 = p2.getName(); return name1.compareTo(name2); } }
closures and types work together
1. prevents trivial errors 2. makes code more readable 3. discovers the impact of change
types help you change with confidence
“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” - James Whitcomb Riley
“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” - James Whitcomb Riley
demo
so how to start using this?
TypeScript not not JavaScript
TypeScript is aligned with ES6
using d.ts we can type existing .js
acc-wizard accounting ace acl acorn add2home adm-zip alertify alt amcharts amplifyjs amqp-rpc amqplib angular-agility angular-bootstrap- lightbox angular-dynamic-locale angular-file-upload angular-formly angular-gettext angular-growl-v2 angular-hotkeys angular-http-auth angular-idle angular-jwt angular-local-storage angular-localForage angular-material angular-meteor angular-notifications angular-notify angular-odata-resources angular-protractor angular-scenario angular-scroll angular-signalr-hub angular-spinner angular-storage angular-toasty angular-translate angular-ui-bootstrap angular-ui-router angular-ui-scroll angular-ui-sortable angular-ui-tree angular-wizard angular.throttle angular2 angularLocalStorage angularfire angularjs-toaster angularjs angulartics animation-frame ansi-styles ansicolors any-db-transaction any-db api-error-handler apn appframework applicationinsights arbiter arcgis-js-api archiver archy asciify aspnet-identity-pw assert assertion-error async asyncblock atmosphere atom-keymap atom atpl auth0.lock auth0.widget auth0 auto-launch autobahn autoprefixer-core aws-sdk axios azure-mobile-services- client backbone-associations backbone-relational backbone.layoutmanage r backbone.paginator backbone.radio backbone backgrid baconjs bardjs batch-stream bcrypt better-curry bgiframe big-integer big.js bigint bigscreen bingmaps bitwise-xor bl blob-stream blocks bluebird-retry bluebird blueimp-md5 body-parser boom bootbox bootstrap-notify bootstrap-slider bootstrap-touchspin bootstrap.datepicker bootstrap.paginator bootstrap.timepicker bootstrap.v3.datetimepi cker bootstrap bowser box2d breeze browser-harness browser-sync browserify bucks buffer-equal buffers bufferstream bunyan-logentries bunyan-prettystream bunyan business-rules-engine byline calq camel-case camljs canvasjs casperjs chai-as-promised chai-datetime chai-fuzzy chai-http chai-jquery chai-subset chai chalk chance change-case chartjs checksum cheerio chocolatechipjs chokidar chosen chroma-js chrome chui circular-json ckeditor classnames cli-color clone codemirror coffeeify colorbrewer colors cometd commander compare-version compression configstore connect-flash connect-modrewrite connect-slashes consolidate constant-case content-type contextjs
interface JQueryStatic { ajax(settings: JQueryAjaxSettings): JQueryXHR; ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR; … (selector: string, context?: Element|JQuery): JQuery; (element: Element): JQuery; (elementArray: Element[]): JQuery; (callback: (jQueryAlias?: JQueryStatic) => any): JQuery; (object: {}): JQuery; (object: JQuery): JQuery; (): JQuery; …
interface Node extends EventTarget { nodeType: number; previousSibling: Node; localName: string; namespaceURI: string; textContent: string; parentNode: Node; nextSibling: Node; nodeValue: string; lastChild: Node; childNodes: NodeList; nodeName: string; ownerDocument: Document; attributes: Attr[]; … lib.d.ts is over 7K LOC of types
demo
this is possible because of gradual typing
interface Findable { whereAreYou(): string; }; class Player implements Findable { ... whereAreYou() { return "Playing Baseball"; } }; var player: Findable = new Player(); player.whereAreYou();
interface Findable { whereAreYou(): string; }; class Player { ... whereAreYou() { return "Playing Baseball"; } }; var player: Findable = new Player(); player.whereAreYou();
class Player { ... whereAreYou() { return "Playing Baseball"; } }; interface Findable { whereAreYou(): string; }; var player: Findable = new Player(); player.whereAreYou();
late interfaces let you write simpler types SimpleBeanFactoryAwareAspectInstanceFactory AbstractSingletonProxyFactoryBean http://www.quora.com/What-are-the-most-ridiculous-Java- class-names-from-real-code
late interfaces help with partial data and object literals
demo
so how do I do it with my code?
if your module is stable use d.ts to add types
if you’re still in flux rename .js to .ts and fix errors then migrate to new structures
demo
TypeScript works with others
jQuery Angular React <JSX>
/// <reference path="react.d.ts" /> interface PlayerProps { name: string; } class Batter extends React.Component<PlayerProps, {}> { render() { return ( <div>{this.props.name} swings!</div> ); } }
Grunt Gulp Make
TYPESCRIPT:=node_modules/.bin/tsc $(TYPESCRIPT_TIMESTAMP): $(TYPESCRIPT_SRC) $(TYPESCRIPT_DTS_SRC) @echo "Compiling typescript..." @$(TYPESCRIPT) $^ --outDir $(JS_PATH) --sourceMap --sourceRoot ../src --noImplicitAny --target ES5 --declaration
VIM Emacs VisualStudio others…
TypeScript is easy to try
Resources Playground http://www.typescriptlang.org/ Tutorial http://www.typescriptlang.org/Tutorial Type Definitions https://github.com/borisyankov/DefinitelyTyped

Why TypeScript?

Editor's Notes

  • #2 I’m going to be giving a talk on “Why Typescript”. I’m not intending this to be a balanced pro-and-con presentation it’s really to present why I think it’s probably a good idea to use TypeScript for any medium sized project+
  • #3 To give you a little context on who I am… I’m a developer at flipp, and we have for years used typed javascript. It wasn’t TypeScript, it was the google closure compiler and standard google closure library. I still really like and appreciate google closure, but more recently TypeScript has really made it stand out for Typed Javascript, and I believe that for most developers, they’re better off using TypeScript.
  • #4 So… before we can say why TypeScript is so good, we need to get a basic introduction to what typescript is… Hopefully you’ve come to this talk because you have some idea, but we can review the fundamentals.
  • #5 So… before we can say why TypeScript is so good, we need to get a basic introduction to what typescript is… Hopefully you’ve come to this talk because you have some idea, but we can review the fundamentals.
  • #6 First of all, it’s a superset of Javascript. It isn’t really a new language, its more a bulked up version of another one. This property is very beneficial for practical purposes, but it also means the real benefits of the language aren’t coming from some big different paradigm shift
  • #7 The other main aspect of typer script is right in the name… it’s typed! I love typed javascript, and I hope after this presentation you will too… So… we’re adding types, and we’re adding new things on top of javascript… what does that actually get us… why is this a good idea?
  • #8 Well… it’s very much like javascript, but the features added are specifically to address the need for scale in development. Developers are making programs that are bigger than plain web pages… this has been true for many years now. However JavaScript up until ES6 really hasn’t been changing much to meet the requirements of bigger teams and bigger codebases. JavaScript was the winner by default. It was designed in under 2 weeks, and it has won because the web won. JavaScript is a hugely popular language because it’s easily available to everyone, and the web is so simple to create visual programs.
  • #9 This is a list of different transpilers that target javascript. It’s from the coffeescript github. The biggest ones are probably dart and coffee script, but clearly developers feel something is missing with JavaScript, yet need to target it as an execution platform. It’s kind of the assembly for the web.
  • #10 So the question is… what does typescript that adds scale. It’s easy to say… javascript can’t scale, and no one really loves it even though they have to use it, but what specifically can TS do to improve code.
  • #11 I think it breaks down into 3 main categories. First, there are alots of trivial little issues that come up when writing JS code, that TS addresses. The second is that TS code is generally easier to read than JS code. And finallly, when it comes to changing things, it’s a lot easier to do so with TS than JS.
  • #12 This first set addresses even small programs and beginners. It isn’t really an issue of scale, except that as small problems grow, you end up with scale issues
  • #13 Adding types to programs prevents bugs by finding them early, hopefully as you type them. These simple bugs sometimes make it into prod and blow up in production, but usually they pop up immediately after loading your web page. It’s better to have your compiler find them quickly.
  • #14 Here’s a simple example. We’re setting the variable message to a string with the inning set to the end. This code looks correct in isolation, and if you saw it in the middle of a function you’d think it was right.
  • #15 What if it turned out that inning wasn’t a string at all. But an object literal? This sort of bug happens all the time. Often there are two code paths, and in one path it’s a number, and in another its an object. Wouldn’t it be nice if this couldn’t happen?
  • #16 It turns out that your code already has types. These types are implicit, and your program relies on them to be correct. You may not know what they are as the programmer, but your program depends on them to exist. Not declaring your types, doesn’t make this problem go away.
  • #17 Heres some more variables. A bool, a number, a string, an array. They all really do have types.
  • #18 In typescript we can use the colon to define what those types are. This looks pretty similar to any other typed language, but you see its not a big change to the JS.
  • #19 JS does have types, its dynamically typed, not untyped. The problem is that the type system that JS has, only knows about ONE type… it’s called the any type? You got a type? It’s the any type.
  • #20 This is what it looks like in TypeScript if you wanted it to be that way. TS types can be exactly JS just by making everything any.
  • #21 This works two ways actually… you can say a variable is a type, but you can also claim a value is a type any… and then it will match always…. Of course if you do this… your program will break.
  • #22 This is a pretty typical javascript function. Takes a pitch and returns a speed.
  • #23 This is what it looks like with types… the type of pitch is a string, and it returns a number. Of course, typescript can figure all this out implicitly through type infrencing.
  • #24 This is what it looks like with types… the type of pitch is a string, and it returns a number. Of course, typescript can figure all this out implicitly through type infrencing.
  • #25 Something that happens quite often in JS code is implicit conversion. Often between numbers and strings.
  • #26 Implicit conversion is a bear trap… typescript removes these kind of trivia items. These bugs are found
  • #27 This is a source of much confusion in JS. The scoping of this is determined by how a function is called, not by where the function was defined.
  • #28 In this example, if you imagine this code inside a member function of some player object. It seems clear that the player is going to catch then throw the ball once the catch promise completes.
  • #29 It turns out that you have to smuggle this value along in a temporary variable to get the lexical scoping you were looking for.
  • #30 In typescript there are what are called arrow functions… the function is defined by a fat arrow, and in this case the lexical scope of the arrow function is bound to this. It used to be that you’d have to use extra variables or a bind call.
  • #31 Prototypes in JavaScript are often an object of confusion, and then to those who understand it, some sort of point of pride
  • #32 This is what a class in javascript looks like. Strangely a function is a constructor, in fact any function is a constructor. And in that constructor this is bound to the newly created object in the new operation. Adding functions to this constructor is done through the prototype property. This property is copied into the proto property of any class instantiated with new, and is what is looked up to find properties. While ok when you get used to it, it isn’t really like other langauges, and some developers choose to avoid new, and instead make their own form of constructor functions that return object literals.
  • #33 This is what a class looks like in TypeScript. It looks far more similar to other programming langauges, and essentially codifies what other frameworks have done to try and make creating classes more regular. You can define the property types, and the constructor is called constructor. The member functions are simply defined as part of the class. Note that this is from ES6 (except for the types) so it should be fairly consistent in thefuture.
  • #34 Inheretence is also a lot simpler with this class context. Previously to do this, people would go through certain prototype exercies to properly do inherentence, but having a super call was usually quite awkward. Here we have a proper super method that we can call in constructors, and also in any other functions. Classes help build structures in the code that will lead to better code quality and having one way to do it will help.
  • #35 var is how we define variables in javascript, and typescript adds two more ways of doing it, both from ES6
  • #36 In this function you see what happens when you try and shadow player with another var in a block. Player ends up being the last value in the loop. Of course you’d never write this code correct? Well, often this can happen when you move logic around, maybe copy paste from somewhere and you get bad results.
  • #37 Let allows you to have block scoping for your variables. This means it wont clobber, and its easier to understand the behaviour
  • #38 Even worse however, is if you forget the var. Now player is on the window somewhere. This leads to all sort of interesting bugs. Typescript of course will detect this sort of bug.
  • #39 Code often has magic numbers, or constants. But you can’t make any constant constant in JS.
  • #40 The const keyword means that Typescript finds this bug and flags it. Note that ES6 will silently fail on this, it enforces the const by just ignoring it… which is one way to avoid a bug… maybe create another one
  • #41 Let’s go on to the next topic. Making the code more readable
  • #42 One thing that types do to help readability. They tell you what the last programmer is telling the compiler.
  • #43 This looks like typical javascript, but to a reader it may not be clear what the scope of the second parameter can be. When we use dynamic things like strings and object literals, that context is lost.
  • #44 Typescript can use enums for example, but it’s not this specific example that’s important it’s that this sort of information is used all the time when understanding code.
  • #45 Often we can use JSDocs. In Closure Compiler these docs are used to check types. However these types always have the chance of rotting in the comments if you don’t use the compiler to check them. I know in ruby devs always want to use YARD to tell the types, it’s because without them it’s very hard to understand what’s going on.
  • #46 So… for readability… everyone knows what this means right? The most important function in the entire web.
  • #47 So when you see this? What does it mean? What’s players? Well its wrapped in a jquery object, but what are we really dealing with.
  • #48 Without types being clear on selected, any of these can actually be the call. Each one of these will be slightly different in meaning.
  • #49 Another pain point in JS is just how the program stucture in the large is put together. Typescript from ES6 adds modules.
  • #50 The canonical way to add new code to the web by an ordered list of script tags doesn’t lend itself to modularization very well.
  • #51 Many people have written loaders to overcome this, some of which do things like this… but hopefully not in production
  • #52 In general, most developers are already compiling their javascript, if not to minify, but to glue together large seconds of code. This is fine, but also further reduces the barrier to TypeScript, which is just another compiler….
  • #53 Even if you compile, I’m sure many of you have seen code like this. This isn’t really a code loading issue, it’s just that you often want to define modules in pieces, and JS gives you no easy way to do namespaces. This code creeps me out….
  • #54 In typescript you can add namspaces. This is the class example earlier wrapped in a module.
  • #55 And we can import and export our namespaces and objects using import and export. There actually are several ways to do this in typescript to be compatable with different ways people like loading their code. Creating a firm module foundation however is a big help in scaling the code.
  • #56 Let and const also help with readability. Especially const when you use it not only on those magic numbers, but also just on varialbes you know won’t be re-assigned. That means readers can easily understand what is changing and what is not changing.
  • #57 Because typescript has IDE support… you can more easily read because you can more easily play. Reading then becomes more interactive, as you can scrub the code to find out what it means and what other values are available.
  • #58 But… I’m saying things are easier to read… and there may be baggage people have about typed langauges. I remember working with Java 15 years ago.. .and hating it.
  • #59 This isn’t a fair comparison for today, but historically dynamic languages had a surge in the mid 2000’s and at the time type langauges like java look like coe on the left, while dynamic languages looked like code on the right. File file = new File augh
  • #60 Even worse was sorting things! This was the way to sort values in Java… Wasn’t this a result of the need for all the types?
  • #61 This isn’t types… it was closures. Dynamic languages used blocks and closures to vastly improve their API design. You didn’t need classes for everything, when functions and object literals could do the job. TypeScript doesn’t need to have those old api’s, and as well see soon, it also dosen’t need to have crazy interface hell to be used nicely.
  • #62 The final part… types help you discover change impact… so you can make changes easily
  • #63 If you can’t read your code easily and play with it, then it’s hard to change with confidence. Test coverage is lovely, but sometimes in the face of real change, it actually can’t help you, because it’s testing where you were before, not where you want to go. Types help a lot when making changes, because they ripple the effects of the changes you make through the codebase correctly.
  • #64 Let’s talk about duck typing, a beloved topic of dynamic languages. It comes down to this quote…. The general idea is that all you need to do is call the function, and if it responds than you’re in.
  • #65 Well… I think there are 2 problems. First it’s more like quack typing… because it typically means you’re only checking one member of the object, the second is that failing at runtime isn’t really typing at all.
  • #66 Let’s look at an example though of how interfaces let you do a real sort of duck typing… Use implicit any…. And discover the types.. Then move to arrays.
  • #67 So how do I get started using TypeScript in my projects?
  • #68 The good news is TS is not not JS, so that means that your existing code will have a relatively easy time with TS
  • #69 TypeScript not only works with JS today, its attempting to stay very close to the ES6 standard.
  • #70 The mechanics for doing this are d.ts files. These files type the untyped and lift them into typescript’s world.
  • #71 Now… in google closure, it was always tough to get coverage across all the libraries you’d want, but typescript has amazing community support. The github defintatelyTyped has several definitions for lots of JS… this is just a to co…
  • #72 Heres an example of what the jQUery one looked like. If Jquery can be typed, your code can be typed.
  • #73 There’s also lib.d.ts which includes all the standard browser envirnment. Never have to worry what window.getSelection does again by googling it.
  • #74 Let’s look at an example of dts.. Then go to playground and show the types.
  • #75 All this ipossible because unlike most typed languages. Typescript really is bolted on top of Javascript, and this means it was designed for tretroactive typing. I think this is acutally pretty special and has neat implications. this lets you have the best of both. Let
  • #76 Let’s look at this class, pretty typically defined, with an interface, but implemented by the class.
  • #77 As you may have noticed in our ducky example, the interfface doesn’t actually need to be implemented by the class, ts figures that out.
  • #78 And in fact, because it’s retroactive, the interface can come later…. This is how d.ts. Works and types code that was already written.
  • #79 This strategy however has implications not just for old code you’re lifiting into typescript. But code you’re writing new. A lot of code in types involves guessing… would you have guessed you needed these class interfaces in java? This is why dynamic languages feel fast to work in, because you’re guessing less. If you can write first and interface after, then you guess les.
  • #80 Also late interfaces let you work with the common issue of partial data. Sometimes you have an entire object, sometimes only part.
  • #82 There are two simple ways to approach adding typescript to your project.
  • #83 First… if like the other libraries, you have stable code.. Then just use d.t.s. This means you get the most benefit for typing without having to change deep existing code.
  • #84 But if your code is still changing, its simple as renaming js to ts… Then compile and fix the errors. Then after that is complete, migrate your classes to new structures. But TS is essentially very much JS, and even the classes are ES6 essentially.
  • #85 Show it just works, then add the classes to the typescript, and type the print…
  • #86 As you can see, TS works well with others. It isn’t microsoft’s kingdom
  • #87 These all work together, Angular 2.0 is written in TypeScript. React even has JSX support in the language.
  • #88 Heres an example if you’re using react, where you can have types in your component definitions.
  • #89 And compilation, it’s supported by grunt, gulp, or even make as we use it. All these build pipelines can be set to watch. Tsc – watch.
  • #90 … if you like make it’s just a command line…
  • #91 And in for IDEs, it is broadly supported. There are plugins for VIM, emacs, but VisualStudio is very good. I’ve been demoin from visual studio code.
  • #92 TS is easy to try, so theres no excuse, Get on it!