Web Front-end Notes - Typescript
- Types
- Classes & Interfaces
- Type Guards
- Index Properties
- Function Overloads
- Optional Chaining
- Generic Types
- Decorators
- Typescript Compiler
Types
typeof
returns the type value in string.
Core Types
The core primitive types in TypeScript are all lowercase!
number
: numbers are by default floats in both JS and TS,+input
is equal toparseFloat(input)
string
boolean
object
: object types are written almost like objects, but with key/type pairs.Array
:Tuple
(introduced in TS):[number, string]
is a tuple type definition.push
method is allowed for Tuple.Enum
(introduced in TS):enum { NEW, OLD }
, default is number type starting with 0 and automatically increment.Any
(introduced in TS): takes away all the benefits that typescript gives you. Used as fallback.
When assigned
null
to variables of primitive types, the Typescript compiler will not complain.
Object Type
1 | // typescript type inference for object type: |
Union & Intersection Types
Union types are types that accept more than 1 type:
1 | let input1: number | string; |
Intersection types allow us to combine types.
1 | type Admin = { |
- In the case of union types, intersection types output the members in common
- In the case of object types, intersection types output the combination.
Literal Types
Literal types are based on core types, like string
or number
, but with poticular value of those types, and often used together with union types:
1 | let resultConversion: "as-number" | "as-text"; |
Discriminated Unions
Build discriminated union by giving every interface an extra property(whatever name you want, typically “kind” or “type”),
1 | interface Bird { |
Type Aliases
type
keyword in Typescript is used to set type aliases:
1 | // use with union types |
Void Type & Never Type
undefined
is not valid return type for functions in Typescript, because Typescript would expect the function to have a return
statement, just not return a value. void
means the function does not return anything, it is allowed that the function does not have a return
statement.
never
type can be used as another return type for functions that never return anything, essentially throw errors or in a infinite loop.
Functions as Types
Function
type allows to assign a function signature to variables, which is quite simular to delegates in C#.
1 | // define a function type that takes 2 number type parameters and return a number |
When function type is used with a callback function, the
void
means the function will not use the returned value, it does not restrict that the function cannot have areturn
statement.
Unknown Type
Any
is the most flexible type in Typescript which basically disables all type checking. unknown
is a bit more restrictive than Any
type, Typescript will have type checkings on it before assign it to another variable with clear type:
1 | let userInput: unknown; |
Classes & Interfaces
Classes
Class exists since ES6, typescript supports it and extends a few use cases.
- Consturctor:
constructor
is the syntax sugar which is called when you call thenew SimpleClass()
to create class instance. this
keyword: refers to the concrete instance of the class in methods. However,this
typically refers to the object that is responsible to call methods. We can declarethis:Department
in method parameters, so that Typescript ensures thatthis
keyword inside a method should always refer to an instance of typeDepartment
.public
is the default modifer for class members.- Shorthand Initialization:
constructor(private id: string, private name: string){};
: declare class fields as constructor parameters. readonly
modifier: it makes sure the field can be only written during initialization.extends
keyword allows class to inherit from another class. One class can only inherit from one parent class.- Always call
super()
first in the inherited class’s own constructors. - With
es7
, we can directly use property definition in class, no need to callsuper
.
- Always call
- Override:
- Define the same method signature in derived class to override the implementation of that method in base class.
- use
protected
keyword to allow derived classes to have access.
- Getters & Setters:
get
keyword is used to create a getter. Getters are defined in method signature, while it is accessed like properties. Getter is by default public.set
keyword is used to create a setter, but it takes avalue
argument.
- Abstract Class:
abstract
keyword can only be used in abstract class to define abstract members.
Interfaces
interface
only exists in Typescript- Interfaces define a structure of objects.
- Typically used as a custom type
- A class can implement an interface by using
implements
keyword, while it can not implement a custom type in the early days due to historical reasons. - Interface can also be used to define a function type:
interface AddFn { (a: number, b: number): number; }
, but it is more common to use custom type to define function types. - Specify optional properties/parameters/methods by adding
?
after the property name. Default value of optional properties isundefined
. - Interface is purely a development feature for writing better codes.
Type Alias vs. Interfaces
- Interfaces are basically a way to describe data shapes, for example, an object.
- Type is a definition of a type of data, for example, a union, primitive, intersection, tuple, or any other type.
Declaration Merging
One thing that’s possible to do with interfaces but are not with types is declaration merging.
1 | interface Song { |
Extends and Implements
In TypeScript, we can easily extend and implement interfaces. This is not possible with types though.
What should I use?
- Interfaces are better when you need to define a new object or method of an object.
- Types are better when you need to create function types.
Type Guards
“typeof” keyword
typeof
is used to check primitive types. However, using typeof
to check custom types always return Object
.
“in” keyword
Instead, we use in
keyword for type guards of custom types.
1 | // The way to check if a property exsits in an object at runtime. |
“instanceof” keyword
Another type guard method is to use instanceof
keyword:
1 | type Vehicle = Car | Truck; |
instanceof
can be used forclass
. However,instanceof
can not be used to checkinterface
, because interfaces are not translated into any javascript code.
Type Casting
Typescript has no idea what type of the element
is:
1 | const element = document.getElementById("user-input"); |
before the variable
1 | const element = <HTMLInputElement>document.getElementById("user-input"); |
“as” keyword after the variable
1 | const element = document.getElementById("user-input") as HTMLInputElement; |
Index Properties
Index types allow us to create objects which are more flexible regarding the properties they might hold.
1 | interface ErrorContainer { |
Every property added the key must be a string and the value must be a string.
Function Overloads
To define function overloads:
- Same function name
- Different parameter amount, types and return type.
Optional Chaining
In Javascript. we often do something like fetchedUserData.job && fetchedUserData.job.title
to securely access job.title
in case it does exist. In typescript, we can use fetchedUserData.job?.title
as the equivalent.
Nullish Coalescing
const storeData = userInput ?? 'DEFAULT';
: means only return “DEFAULT” only when userInput
is null
or undefined
.
Generic Types
1 | function merge<T, U>(objA: T, objB: B); |
Constraints
Use extends
to set constraints for type arguments.
1 | function merge<T extends object, U extends object>(objA: T, objB: B); |
“keyof” Constraint
Type argument U
should be one of existing key of type T
:
1 | function extractAndConvert<T extends object, U extends keyof T>(); |
Typescript built-in generic utility types
These types only exsits in typescript world.
Partial<T>
Readonly<T>
- …
Decorators
- Decorators execute when defining classes. It does not execute at runtime.
- Use
@
to use the decorators - Decorator factories runs in top-bottom order, while decorators run in bottom-top order.
Class Decorators
- Class decorators are functions with one argument of target constructor.
- Class decorators can return a new class to extend the original class with extra logic.
Property Decorators
Property decorator receives 2 arguments:
- target: prototype of the object if attached to an instance property, or the constructor function if attached to a static property
- property name: property name of
string
orsymbol
type.
Accessor Decorators
Accessor decorator receives 3 arguments:
- target: prototype of the object if attached to an instance accessor, or the constructor function if attached to a static accessor
- name: name of the accessor itself of type
string
orsymbol
. - property descriptor: of Typescript built-in type
PropertyDescriptor
.
Methods Decorators
Method decorator receives 3 arguments:
- target: prototype of the object if attached to an instance method, or the constructor function if attached to a static method
- name: name of the method of type
string
orsymbol
. - property descriptor: of Typescript built-in type
PropertyDescriptor
.
Accessor and methods decorators can return a new PropertyDescriptor
to replace the original one.
Parameter Decorators
Parameter decorator receives 3 arguments:
- target: prototype of the object if attached to an instance method, or the constructor function if attached to a static method
- name: name of the method in which the parameter is used, of type
string
orsymbol
. - position of the parameter: of type
number
, index starting with 0.
Typescript Compiler
Watch mode:
Use tsc app.ts --watch/-w
to watch changes for a single file.
Compile entire project:
tsc --init
creates a tsconfig.json
file for the working directory and considers it as a typescript project, run tsc
will compile all the files under the folder/sub-folders.
tsconfig.json
tsconfig.json
tells typescript how the compiler behaves.
"exclude": ["node_modules"]
: accept an array of files and folders to be excluded. It accepts wildcard pattern.node_modules
is excluded by default."include": []
: accept an array of files and folders to be included. If it is set, everything not covered byinclude
will not get compiled."files": []
: allows to point the individual files of specific paths.
compilerOptions section
"target": "es5"
: tells typescript in which ES version you want to compile the code to."es5"
is the default value."lib": ["dom", "es6", "dom.iterable", "scripthost"]
: allows to specify which default objects and features typescript knows. Typescript does not know anything aboutDOM
objects by default. However the default value depends on thetarget
option. For example, fores6
, it by default includes all the features that are globally available in ES6, and it assumes that all DOM APIs are available. Basically the default libs allow your compiled javascript run in the browser."allowJs": false
: allow to include javascript files in the complaination"checkJs": false
: will not compile javascript files but will check syntax and report errors."sourceMap": false
: helps with debugging. If set totrue
, the compiler will also generate.js.map
file as well, which acts as a bridge between javascript and typescript. The browser will also load the typescript file and allow debugging."outDir": "./"
: tell the typescript compiler where the created javascript files should be stored."rootDir": "./"
: make sure typescript does not look into others folders."removeComments": false
: will remove any comments after compilation."noEmit": false
: does not generate any javascript files, like dry run."noEmitOnError": false
: if set totrue
, typescript will stop generating any outputs if any error detected."strict": false
: If set totrue
, it enables all following strict type-checking options:"noImplictAny": false
: If set totrue
, it ensures that we have to be clear about the types of the parameters that in no way can be inferred."strictNullChecks": false
: If set tofalse
, the compiler will not complain a potential null value variable."strictFunctionTypes":
:"strictBindCallApply":
: If set totrue
, it checks if it makes sense(match arguments) of the arguments you passed tobind
,call
andapply
functions."strictPropertyInitialization":
:"noImplicitThis":
:"alwaysStrict":
: If set totrue
, it controls that the generated javascript code always use “strict” mode.
"noUnusedLocals": false
: If set totrue
, the compiler will give warnings on unused local(like within functions) variables, stops compiling."noUnusedParameters": false
: If set totrue
, the compiler will give warnings on unused function parameters, stops compiling."noImplicitReturns": false
: If set totrue
, every path of a function is forced to have areturn
statement, otherwise it will be considered as errors.
Debugging with Visual Studio Code
- Install
Debugger for Chrome
extension in VS Code. - Enable
"sourceMap": true
option intsconfig.ts
file. - In your project, click debug and select “Chrome” as the environment.
- In
.vscode/launch.json
file, make sure theurl
value points to the right local url for you local web server. - Set some break points, and click Start Debugging.
Declaration Files
Use declare module
to define type definitions for packages that do not come with built-in types. See details here.