- Basic syntax:
function name(variable: type): type
- Numbers:
number
(according to the handbook, it is to be in lower case becausenumber
is the primitive type, whileNumber
is the object type) - Strings:
string
- Typed arrays:
number[]
- The
any
type literally means anything. It may well be omitted; the only use of it is to prevent errors when interacting with JS code. - The
unknown
type is similar to theany
type, except something ofunknown
type cannot be assigned to a variable of some other type, so the "any" type checking is not propagated. void
is only used to denote that a function returns nothing (undefined
ornull
).abcDef() as SomeType
asserts the type of the result to a certain type when you know better than the static checker. TypeScript typically won't allow you to assert unless the function returnsany
, or has no definite return type, like if a random function is involved.??
, unlike||
, falls back only fornull
orundefined
, not for all falsy values. (edit: this is in JS proper now.)a?.b
accessesa.b
only ifa
is not null.a[d]
is your standard JS. Since?
is already a thing (it's a ternary operator, e.g.a ? b : c
), and whitespace is nothing in JS,a?[d]
doesn't work. You need to writea ?. [d]
to accessa[d]
ifa
is not null.- ...Or,
a?
can denote thata
is nullable. Soa ? : string
is totally fine, buta ? boolean : string
is totally not fine. Imagine that. - The
never
type is used to make sure nothing is ever assigned to it, includingnull
, or to make sure a function never returns anything, includingnull
. It is a bit like: undefined
, but if you actually usefunction foo(): undefined
, you are required toreturn undefined
, which is a bit odd.
- Enums compile down to plain old objects.
- Although
enum Foo { A = 1, A = 2, A = 3 }
won't compile, if it were to compile, it would compile to an object that's a bit confused:{ 1: "A", 2: "A", 3: "A", A: 3 }
.
Like in any other sane language, an interface is an abtract class with no code in its methods.
interface Foo {
bar: number;
setBar(baz: number);
}
class FooImpl implements Foo {
setBar(baz: number) { // Only constructor variables can be `private`
this.bar = baz;
}
}
Foo
is never compiled to the resulting JS file. As far as the script is concerned, Foo
never existed.
Classes can themselves have a "static" interface imposed on their constructors:
interface Foo {
new (bar: number);
}
class Foo2 {
constructor(bar: number) { }
}
var CheckedFoo2: Foo = Foo2; // This may be a bit messy
var foo2Instance = new CheckedFoo2(1);
Private methods cannot be declared in interfaces. Interfaces can only specify public methods.
The thing that is "function interface" in TS controls what is required of an object that is passed into the function. Say you have
function foo(bar: object): number {
return bar.baz;
}
It is implicit that the object bar
must have an attribute baz
that is a number. Therefore, it can be expressed as an interface
interface Bar {
baz: number;
optionalParameter?: boolean; // If it is supplied, it must be a boolean
}
function foo(bar: Bar): number {
return bar.baz;
}
Interfaces are good for catching typos. It can also be used this way, on function expressions:
interface FuncSignature {
(foo: string, bar: string): number;
}
// The function needs the same signature as its interface.
var func: FuncSignature = function (foo: string, bar: string): number {
return 5;
}
var func: FuncSignature
can be saved and used on multiple functions, so you might save some work by doing so.
NOTE: Don't use the types Number
, String
, Boolean
, or Object
"These types refer to non-primitive boxed objects", aka you should just ask for the primitive types number
, string
, boolean
, and object
.
From the Handbook, a variable can be assigned a function, then be assigned another function with fewer [but the same types of remaining] parameters than it:
var x = (a: number) => 0;
var y = (b: number, s: string) => 0;
y = x; // "every parameter of x has a corresponding compatible parameter in y, so the assignment is allowed"
x = y; // "y has a required second parameter that x does not have, so the assignment is disallowed"
Incidentally, since the handbook talks about 'required parameters', this is valid:
var x = (a: number) => 0;
var y = (b: number, s?: string) => 0; // Optional s
y = x; x = y;
If for some reason you need to make an interface for an already-typed array, you may:
interface StringArray {
[index: number]: string;
}
var foo: StringArray = ['foo', 'bar'];
Like classes, interfaces can be extended using the extends
keyword.
If you use extends
as a variable name in your existing JS files, you are an idiot.
Interfaces do not need to be used by any class before it is used. This example shows an interface Foo
simply being used to check the ways the variable c
is used. There is no C
class.
interface Foo {
bar: number;
}
var c: Foo;
c.bar = 5;
Classes can have private members: number;
and static members: numbers
.
They can also have getters and setters, which downpiles to the same thing in ES6, for which you may need a shim.
class Foo {
private _bar: string;
static kek: number;
get bar(): string {
console.log(Foo.kek); // undefined (which is a number, obviously, since we declared it as such)
return this._bar;
}
set bar(baz: string) {
this._bar = baz;
}
}
Unlike ES6 (before node v12's version of ES6 anyway), it is valid syntax to set an instance's property directly inside the class, outside of any method. The compiler appears to convert it to a constructor, with the constructor
at the end of everything else.
// TypeScript
class Foo {
bar = 1;
constructor() {
this.bar = 2;
}
bar = 3;
}
// Transpiled code
var Foo = (function () {
function Foo() {
this.bar = 1;
this.bar = 3;
this.bar = 2; // Notice the constructor body is now last
}
return Foo;
})();
// The effect is every (new Foo) has a bar of 2
Classes can be extended with multiple superclasses, aka. Mixins; but, for some reason, we use the keyword implements
instead of extends
.
This treats the classes as interfaces, and only uses the types behind [the mixin classes] rather than the implementation.
Decorators can all be on the same line, i.e. @f @g
Classes with only static variables can be interfaces.
class Point {
x: number;
y: number;
}
interface Point3d extends Point { // Magic
z: number;
}
A generic class is defined as such:
class Foo<T> {
someMethodThatUsesT(bar: T) {
alert(bar);
}
}
And a generic class is instantiated as such:
var newInstance = new Foo<string>(); // you can now call someMethodThatUsesT with only strings.
Microsoft tells you how to write typescript with performance.