Basic Types
Boolean
, Number
, String
, Array
, Tuple
, Enum
, Any
, Void
, Null
, Undefined
, Never
1 | // Boolean |
Note:
By default
null
andundefined
are subtypes of all other types, that means you can assignnull
andundefined
to something likenumber
However, when using
--strictNullChecks
flag,null
andundefined
are only assignable tovoid
and their respective types. This helps avoid many common errors. In cases where you want to pass in either astring
ornull
orundefined
, you can use theunion type
string | null | undefined
.
Type assertions
1 | let someValue = 'this is a string' |
Variable Declarations
Interfaces
One of TypeScript’s core principles is that type-checking focuses on the shape that value have. This is sometimes called ‘duck typing’ or ‘structural subtyping’. In TypeScript, interface fill the role of naming these types and are a powerful way of defining contracts within your code as well as contracts with code outside your project.
1 | function printLabel(labelObj: { label: string }) { |
Optional Properties
1 | interface SquareConfig { |
Readonly Properties
1 | interface Point { |
Note: Readonly Array
1 | let a: number[] = [1, 2, 3] |
You can’t assign the entire ReadonlyArray
back to a normal array. Instead, you could do this:
1 | a = ro as number[] |
Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the
target type
doesn’t have, you’ll get an error.
Adding Index Signature
Add a string index signature if you’re sure that the object can have some extra properties that are used in some special way.
1 | interface SquareConfig { |
Function Types
To describe a function type with an interface, we give the interface a call signature
. This is like a function declaration with only the parameter list and return type given. Each parameter in the parameter list requires both name and type.
1 | interface SearchFunc { |
Indexable Types
Similarly to how we can use interfaces to describe function types, we can also describe types that we can ‘index into’ like a[10]
or ageMap['daniel']
. Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing.
1 | interface StringArray { |
Class Types
Implementing an interface.
One of the most common uses of interfaces is explicitly enforcing a class meets a particular contract.
1 | inerface ClockInterface { |
Interface describe the public side of the class, rather than both the public and private side. This prohibits you from using them to check that a class also have particular types for the private side of the class instance.
Difference between the static and instance side of classes.
When working with classes and interfaces, it helps to keep in mind that a class have two types: the type of static side and the type of the instance side.
When a class implements an interface, only the instance side of the class is checked.
Notice: constructor sits in the static side, it is not included in this check.
Extending Interfaces
1 | interface Shape { |
An interface can extend multiple interface, creating a combination of all of the interfaces.
1 | interface Shape { |
Hybrid Types
1 | interface Counter { |
Interface Extending Classes
When an interface type extends a class type it inherits members of the class but not their implementations. It is as if the interface has declared all of the members of the class without providing an implementation. Interface inherits even the private and protected members of a base class. This means that when you create an interface that extends a class with private or protected members, that interface type can only be implemented by that class or a subclass of it.
1 | class Control { |
Classes
Example:
1 | class Greeter { |
Class Inheritance
1 | class Animal { |
Public, Private, Protected Modifiers
Public by default
Private: when a member is marked
private
, it cannot be accessed from outside of its containing class.
Protected: The protected modifier acts much like the
private
modifier with exception that members declaredprotected
can also be accessed by instance of deriving classes. Namely theprotected
property can be used in instance method.
Readonly Modifier
Readonly properties must be initialized at their declaration or in the constructor.
Accessors
TypeScript supports getters/setters as a way of intercepting accesses to a member of an object.
1 | class Employee { |
Static Properties
1 | class Grid { |
Abstract Classes
Abstract classes are base classes from which other classes may be derived. They may not be instantiated directly.
Unlike an interface, an abstract class may contain implementation detail for its members. The
abstract
keyword is used to define abstract classes as well as abstract methods within an abstract class.
1 | abstract class Animal { |
Methods within an abstract class that are marked as abstract do not contain an implementation and must be implemented in derived classes.
Abstract methods share a similar syntax to interface methods. Both define the signature of a method without including a method body.
1 | abstract class Department { |
Advanced Techniques
Constructor Functions
When you declare a class in TypeScript, you are actually creating multiple declarations at the same time. The first is the type of the
instance
of the class.
1 | class Greeter { |
Here when we say
let greeter: Greeter
, we’re usingGreeter
as the type of instance of the classGreeter
. Almost we use the class constructor as a type.
Using a class as an interface
A class declaration creates two things: a type representing instances of the class, and a constructor function.
1 | class Point { |