This guide presents a syntax comparison between C# and JavaScript (ES6/ES2015 minimum) / TypeScript.
You'll find other guides and a general explanation here.
Why TypeScript ? As a C# developer, you'll love it, and we explain why here. This guide tells clearly when a feature is TypeScript specific. Eveything else is standard JavaScript.
Data declarations
In JavaScript, variables can be declared globally.
Since ES6, use only the
let
keyword.
/* C# */ var myData = "csharp";
/* JavaScript */ let myData = "js";
ES6 introduced global constants in JavaScript. Unlike C#, complex values can be used and therefore manipulated.
/* C# */ const string myData = "csharp"; readonly User myUser = new User();
/* JavaScript */ const MY_DATA = "js"; const MY_USER = new User();
Simple data types
Unlike C#, data types are dynamic in vanilla JavaScript (a variable can change its type at any time), and you don't need to specify them (they are automatically detected). TypeScript adds manifest and static types. All numbers share the same type in JavaScript.
/* C# */ bool userMan = true; int userAge = 81; float userAverage = 10.5; string userName = "Henri Bergson";
/* TypeScript */ let userMan: boolean = true; let userAge: number = 81; let userAverage: number = 10.5; let userName: string = "Henri Bergson";
In addition to null
, JavaScript has the undefined
type,
and NaN
(Not a Number). They are errors, so do not use them.
String details
Unlike C#, you can use either single or doubles quotes for strings in JavaScript. ES6 introduced template literals : new backtick quotes for variable interpolation and allowing line breaks. Avoid classic concatenation in JavaScript, as it's confusing with additions and will lead to type errors.
/* C# */ string userFullName = $"{userFirstName} {userLastName};
/* JavaScript (except type) */ let userFullName: string = `${userFirstName} ${userLastName}`;
Also useful to manage simple and double quotes in the same string.
/* JavaScript (except type) */
let HTMLTemplate: string = `<p class="content">I'm Henri !</p>`;
Data lists
Unlike C#, size of arrays is always dynamic in JavaScript, so you can add items at any time.
/* C# */ string[] userBooks = {"Book 1", "Book 2"}; // Use List if you need to add items userBooks[0]; userBooks.Length;
/* JavaScript (except type) */ let userBooks: string[] = ["Book 1", "Book 2"]; userBooks.push("Book 3"); userBooks[0]; userBooks.length;
C# dictionaries are called objects in JavaScript, with string keys.
/* C# */ Dictionary<string, string> user = new Dictionary<string, string>(); user.Add("firstName", "Henri"); user.Add("lastName", "Bergson"); user["firstName"];
/* JavaScript */ let user = { firstName: "Henri", lastName: "Bergson" }; user.firstName;
As a JavaScript object is like a literal instance, you can use TypeScript interfaces as its type.
/* TypeScript */
interface User {
age: number;
name: { first: string, last: string };
}
let user: User = {
age: 81,
name: { first: "Henri", last: "Bergson" }
};
ES6 introduced new collections : Map, Set, WeakMap, WeakSet.
Blocks
Same syntax for conditions in C# and JavaScript.
Since ES6, thanks to let
, variables are block-scoped.
Unlike C#, a child block variable can overrirde a parent block variable in JavaScript.
/* C# */ for (int i = 0; i < 10; i++) {}
/* JavaScript (except types) */ for (var i: number = 0; i < 10; i++) {} i; // 10, error prone for (let i: number = 0; i < 10; i++) {} i; // undefined
Iteration
is simplified in ES6.
Do not use for ... in
in JavaScript, it's not for arrays.
/* C# */ for (var value in userBooks) {}
/* JavaScript */ for (let value of userBooks) {}
Another option for complex iterations (with values and keys, only for arrays).
/* C# */ for (int i = 0; i < books.Count; i++) { books[i]; }
/* JavaScript (except types) */ books.foreach( function (value: string, index: number) {});
Functions
In JavaScript, you can access parent scopes directly.
/* JavaScript (except types) */
let myData: string = "value";
function myMethod(): void {
myData; // "value"
}
Unlike C#, no overloading in JavaScript (a function can only have one definition), and parameters are always optional. ES6 introduced default values. TypeScript allow automatic required arguments without manual checking (one of the only major differences with vanilla JS).
/* C# */ void myMethod(string required, string optional = "default") {}
/* JavaScript */ function myMethod(requiredToCheck, optional = "default"): void { /* Simple comparison is important * as it can be undefined too */ if (requiredToCheck == null) {} } /* TypeScript */ function myMethod(requiredForReal: string, optional: string = "default"): void {}
ES6 introduced a shorter anonymous functions syntax, named arrow functions, equivalent to lamba expressions in C#.
/* C# */ numbersList. .Where(value => value > 2);
/* JavaScript (except type) */ numbersList .filter((value: number) => value > 2);
Built-in methods
Some basic methods.
/* C# */ myEmail.IndexOf("@"); myEmail.Replace("@", " at "); myEmail.Substring(0, 5); myEmail.Length; Int32.Parse("10");
/* JavaScript */ myEmail.strpos("@"); myEmail.replace("@", " at "); myEmail.substring(0, 5); myEmail.length; parseInt("10");
When a function seems to be called directly, like parseInt()
,
it's because the global object is implicit : window.parseInt()
.
Do use the shorthand, as the global object is not always window
.
Classes
ES6 introduced classes syntax,
to simplify object oriented programming in JavaScript.
Properties are directly created in the constructor, and unlike C#,
you must refer to them via this
.
Pre-declared properties and visibility modifiers are missing in ES7 :
they may appear in future JavaScript versions, but
TypeScript allows them right now.
/* C# */ public class User { public string FirstName; public User(string firstName) { FirstName = firstName; } public void SayHello() {} } User myUser = new User("Henri"); myUser.FirstName; myUser.SayHello();
/* JavaScript + TypeScript */ class User { public firstName: string; public constructor(firstName: string) { this.firstName = firstName; } public sayHello(): void {} } let myUser: User = new User("Henri"); myUser.firstName; myUser.sayHello();
In JavaScript inheritance, parent call is required in the child constructor, and you can override methods (no specific keyword required, unlike C#).
/* C# */ public class Editor: User { public Editor(string firstName) { base(firstName); } public override void SayHello() { base.SayHello(); } }
/* JavaScript (except types) */ class Editor extends User { public constructor(firstName: string) { super(firstName); } public sayHello(): void { super.sayHello(); } }
Like in C#, getters and setters have a special syntax in JavaScript.
/* C# */ public class User { private string name; public string Name { get { return name; } set { name = value; } } } User myUser = new User("Henri"); myUser.Name; myUser.Name = "New name";
/* JavaScript (except types) */ class User { protected _name: string; public get name(): string { return this._name; } public set name(newName: string) { this._name = newName; } } let myUser: User = new User("Henri"); myUser.name; myUser.name = "New name";
Same syntax for static methods in C# and JavaScript.
/* JavaScript (except type) */
class Utilities {
static filter(): void {}
}
Utilities.filter();
TypeScript adds abstract classes and interfaces.
/* C# */ interface Movable { void Move(); } public class Vehicle: Movable { public void Move() {} } public abstract class Test {}
/* TypeScript */ interface Movable { public Mve(): void; } class Vehicle implements Movable { public move(): void {} } abstract class Test {}
Namespaces
Namespacing is directly managed by the loading system since ES6 :
if there is the export
keyword or
import
keyword,
then you are not anymore in the global scope.
Be careful : .js
extension is required in JavaScript imports, but in TypeScript,
as you'll need to manage both .ts
in development and .js
in production,
it's better to configure the loader to automatically add the right extension.
/* C# */ // User.cs namespace Accounts { public class User {} } // script.cs using Accounts; User myUser = new User();
/* JavaScript (except type) */ // User.ts export class User {} // script.ts import { User } from "./module"; let myUser: User = new User();