
An overview of Microsoft TypeScript Hilde Verbeek January 27, 2020 1 Introduction TypeScript is a language developed by Microsoft and first released in 2012, that is meant as an improved version of JavaScript. TypeScript is a superset of JavaScript, meaning ev- ery JavaScript program is also a valid TypeScript program. TypeScript programs compile to JavaScript, so can be run in web browsers making them useful for the same purposes as JavaScript, with web development at its core.[1] TypeScript was created with several similar languages for the same purposes existing, such as CoffeeScript and Google's Dart. However, TypeScript has become one of the most popular languages for web development over the years, ranking as the tenth most used language in Stack Overflow's 2019 survey.[2] The language was developed after Microsoft developers felt the need for a better alternative to JavaScript. The language aims to mitigate the shortcomings of JavaScript, mainly with regards to its type system (which is where the languages gets its name). The main feature to achieve this, is the addition of a static type checker, but besides this, TypeScript adds many other features to improve the quality when one would normally use JavaScript. This report will look at some of the features of TypeScript, and analyze and evaluate the usefulness of the type system. It will end with some of the advantages and drawbacks to using TypeScript over pure JavaScript or other alternatives. The entire language specification of TypeScript is available online. This report royally refers to it for certain details, whereas some others are the result of experimenting with the TypeScript compiler.[3] 2 Language Features Because TypeScript is a syntactic superset of JavaScript, its possibilities and purposes are much the same. TypeScript-specific features are mostly meant to improve the development process of writing a typical JavaScript application, with a focus on adding a static type checker, as well as generally extending and improving JavaScript's type system. Other features include syntactic sugar to improve existing language concepts. 2.1 Programming paradigm TypeScript is classified as a multi-paradigm language. Like JavaScript, it is at its core an imperative language, that contains features that allow for different paradigms. The inclusion of classes and objects allows for an object-oriented approach. TypeScript's static type checker, as well as some other features enhance this. Furthermore, there are multiple features that allow functional programming approaches, such as functions as first-class citizens. TypeScript's type system also allows ways to easily define algebraic data types.[4] 1 2.2 Type system TypeScript's essential addition to JavaScript, and its namesake, is the static type checker intro- duced by the compiler. JavaScript's own type system is a loosely-, dynamically-typed system that is often at the core of criticism directed at the language. TypeScript seeks to eliminate these problems, by introducing a compile-time static type checker, using a system commonly known as gradual typing. The programmer is allowed to add (optional) type annotations to variables, constants, parameters and return values; if no type annotation is given, the compiler attempts to infer the type from context. Using the provided or inferred types, the compiler statically checks the usage of values, and raises errors upon misuse. The enforced type system is more strict and safe than JavaScript's dynamic typing system: for example, it is strongly typed, and as such does not allow for every value to be used in every context. The type system is further detailed in the next section. 2.3 Scalability One goal of TypeScript and specifically its static type checker, is to improve the scalability of applications. There are multiple ways this is helped: for one, static type checking prevents the misuse of functions with regards to parameter and return types, which becomes more and more likely in large applications, especially in teams. In pure JavaScript, this kind of type errors can often goes uncaught. Furthermore, TypeScript's compiler allows for the creation of declaration files (similar to C/C++'s header files) that only describe the types of functions and values exported by a module. These declaration files allow for efficient module or library development, as the applications using these modules can refer to the declaration files during type checking. 3 Type System 3.1 The JavaScript type system To understand TypeScript's static typing, it is first important to understand how JavaScript itself handles types. Remember that a TypeScript program compiles to JavaScript, so Type- Script is actually (sort of) subjected to these rules as well; however, it adds guards at compile time to ensure types are not used in \unsafe" ways that will cause weird or unexpected results when run by a JavaScript interpreter. 3.1.1 Primitive and object types JavaScript has a limited amount of types. Some are straight-forward primitive types such as number, string and boolean. The types null and undefined correspond to their equally- named values. The type object is applied to any JavaScript object, including arrays and user- defined types constructed with new. This means that there is no way to distinguish between object types at runtime; the reasons and implications of this become clear later on.[5] 3.1.2 Weak typing and type coercion A typing feature of JavaScript, that is commonly referred to as \weak typing", is one of the problematic features that TypeScript attempts to mitigate. Weak typing means that in any application of a value, the interpreter will attempt to find a way to use it, and produce a value. This process is called type coercion. An example is the expression "3" * "4": there is no way to multiply strings, so the interpreter casts the values to numbers, and the result is 12 (a number). 2 This is likely not the intention of the programmer, as they would probably actually provide values of type number if it was. In case one of the operands cannot be properly parsed as a number, such as in "3" * "foo", it will become NaN, and so will the outcome of the expression. This could cause serious problems in a program. While the result of this expression should still be clear, there are much worse examples where type coercion produces extremely unexpected and arbitrary-seeming results. [6] 3.1.3 Duck typing A typing pattern that is certainly not unique to JavaScript, is called \duck typing". After the poet James Whitcomb Riley, who wrote \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.", duck typing means that any object can be treated as a desired type, as long as it more or less exhibits the behavior of said type. To call a function, or access a property of an object, the object's type or structure does not matter as long as it contains the requested property.[7] Consider the following example: function Person(name) { this.name = name; } Person.prototype.greet = function() { console.log("Hello, " + this.name); } var people = []; people.push(new Person("Amy")); people.push(new Person("Josh")) people.push({greet: function() {console.log("I'm a duck!");}}); for(var person of people) person.greet(); This code will run fine, even though the third object is not defined as a Person and has its own greet method instead. For each of the objects, JavaScript will simply check if it has a greet method and run it, regardless of how it was defined. In certain other languages, especially statically-typed ones, such an approach would not work, as it would require a shared definition of the method, for instance in a superclass. The behavior can be used for good and bad: one one hand, it allows for a very simple definition of interfaces (without explicitly defining the interface beforehand) to use a strategy pattern. However, the lack of static type checking makes it much more prone to runtime errors (eg. when some of the methods are not defined by an implementation) and occasionally harder to understand as programmer.[8] On top of that, the lack of static definitions and protections (eg. non-public interfaces and unoverridable methods) make it more prone to malicious usage. 3.2 Overview of TypeScript types TypeScript introduces a system of static type checking, that is performed as the code is compiled to JavaScript, in order to make it more \developer-proof". The static checker is subject to much stricter rules than pure JavaScript: the previous example of the expression "3" * "4" will produce a compiler error: The right-hand side of an arithmetic operation must be of type `any', `number', `bigint' or an enum type. However, it should be noted that despite the compiler error it still produces output, as it is still valid JavaScript code that will have no trouble running. 3 We will look at a subset of typing features and concepts to better understand how TypeScript handles it. 3.2.1 Type annotations and type inference TypeScript checks type correctness from the bottom up. On the lowest level, the type of simple values is often obvious: "foo" is obviously a string, and 42 is obviously a number. From here on out, the types of more complex expressions can be inferred: for instance, the result of a number added to a number, is obviously itself a number. This process is called type inference. When declaring functions, variables and constants, the programmer can choose to supply a type annotation, to declare the type of said value. If the type annotation is omitted, in many cases it can and will still be inferred by the compiler, from its initial value.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages10 Page
-
File Size-