-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from ReCoded-Org/typescriptmodule
Module 8: Typescript
- Loading branch information
Showing
11 changed files
with
1,152 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,30 @@ | ||
# curriculum-backend-readings | ||
# Module 8: TypeScript | ||
|
||
Last revised: 14/06/2022 | ||
|
||
## Summary | ||
|
||
Students learn to use TypeScript, an essential and marketable skill in today’s JavaScript | ||
landscape. This variant of JavaScript provides type safety, allowing developers to write | ||
more scalable and understandable applications. Students apply their learning of | ||
TypeScript concepts using the Nest.js framework in comparison to Express.js. | ||
|
||
## Outline | ||
|
||
- 1 [Introduction to TypeScript [R]](../module8-typescript/r1-introduction-to-typescript/README.md) | ||
|
||
- 1.1 [Everyday Types [R]](../module8-typescript/r1.1-everyday-types/README.md) | ||
|
||
- 1.2 [Advanced Types [R]](../module8-typescript/r1.2-advanced-types/README.md) | ||
|
||
- 1.3 [TypeScript Compiler [R]](../module8-typescript/r1.3-typescript-compiler/README.md) | ||
|
||
- 2 [TypeScript with Node and Express [R]](../module8-typescript/r2-typescript-node-express/README.md) | ||
|
||
- 2.1 [Backend frameworks with TypeScript [R]](../module8-typescript/r2.1-backend-frameworks-typescript/README.md) | ||
|
||
- 2.2 [TypeScript Cart [L]](../module8-typescript/r2.2-typescript-cart/README.md) | ||
|
||
- 2.3 [NestJS Task Management App [L]](../module8-typescript/r2.3-nestjs-task-management/README.md) | ||
|
||
- 3 [Summary [R]](../module8-typescript/r3-summary/README.md) |
This file was deleted.
Oops, something went wrong.
180 changes: 180 additions & 0 deletions
180
module8-typescript/r1-introduction-to-typescript/README.md
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
# Advanced Types | ||
|
||
We have learned quite a bit about Types so far, but when it comes to large-scale projects there are more advanced types that help us write more robust code which will dive into now. The objectives of this lesson are: | ||
|
||
1. Viewing practical usage examples of advanced Types | ||
2. Understanding when to use advanced Types | ||
|
||
## Interfaces | ||
|
||
An interface declaration is another way to name an object type. Interfaces can be used interchangeably with type aliases and simple object types. | ||
|
||
```ts | ||
interface Point { | ||
x: number; | ||
y: number; | ||
} | ||
|
||
function printCoord(pt: Point) { | ||
console.log("The coordinate's x value is " + pt.x); | ||
console.log("The coordinate's y value is " + pt.y); | ||
} | ||
|
||
printCoord({ x: 100, y: 100 }); | ||
``` | ||
|
||
Like when we used a type alias above, the example works just as if we had used an anonymous object type. TypeScript is only concerned with the structure of the value we passed to `printCoord` - it only cares that it has the expected properties. | ||
|
||
You can also define properties in an interface to be optional using `?` or non-editable by specifying `readonly`. | ||
|
||
```ts | ||
interface UserInterface { | ||
readonly id: number; | ||
name: string; | ||
age?: number; | ||
} | ||
|
||
const user1: UserInterface = { | ||
id: 1, | ||
name: "John", | ||
}; | ||
``` | ||
|
||
Interfaces can be used with functions as well. | ||
|
||
```ts | ||
interface MathFunc { | ||
(x: number, y: number): number; | ||
} | ||
|
||
const add: MathFunc = (x: number, y: number): number => x + y; | ||
const sub: MathFunc = (x: number, y: number): number => x - y; | ||
``` | ||
|
||
## Classes | ||
|
||
TypeScript offers full support for the class keyword introduced in ES2015. As with other JavaScript language features, TypeScript adds type annotations and other syntax features to allow you to express relationships between classes and other types. Just like any other OOP language, classes have members or fields and a constructor function is used to instantiate the objects of this class with initial field values. Classes can also have member functions. | ||
|
||
```ts | ||
// Class with constructor | ||
class Person { | ||
id: number; | ||
name: string; | ||
|
||
constructor(id: number, name: string) { | ||
this.id = id; | ||
this.name = name; | ||
} | ||
|
||
greet(message: string) { | ||
console.log(message + this.name); | ||
} | ||
} | ||
|
||
const alice = new Person(1, "Alice Green"); | ||
alice.greet("Hello"); | ||
``` | ||
|
||
You can use an `implements` clause to check that a class satisfies a particular interface. | ||
|
||
```ts | ||
interface PersonInterface { | ||
id: number; | ||
name: string; | ||
register(): string; | ||
} | ||
|
||
class Person implements PersonInterface { | ||
id: number; | ||
name: string; | ||
|
||
constructor(id: number, name: string) { | ||
this.id = id; | ||
this.name = name; | ||
} | ||
|
||
register() { | ||
console.log(`${this.name} is now registered`); | ||
} | ||
} | ||
|
||
const alice = new Person(1, "Alice Green"); | ||
const mike = new Person(2, "Mike Jordan"); | ||
|
||
alice.register(); | ||
mike.register(); | ||
``` | ||
|
||
Classes may extend from a base class. A derived class has all the properties and methods of its base class, and also defines additional members. | ||
|
||
```ts | ||
class Employee extends Person { | ||
position: string; // additional member of this subclass | ||
|
||
constructor(id: number, name: string, position: string) { | ||
super(id, name); | ||
this.position = position; | ||
} | ||
} | ||
|
||
const emp = new Employee(3, "Shawn", "Developer"); | ||
emp.register(); | ||
``` | ||
|
||
A field of a class can be one of the following: `public`, `private`, `protected`, or | ||
`readonly`. | ||
|
||
- `public`: This field can be read to and written as normal. | ||
- `private`: Only accessible by the instance of the class. For example, this variable cannot be accessed by any code other than the functions in the class. | ||
- `protected`: Similar to `private`, but subclasses can access the field. | ||
- `readonly`: This field can only be read, but it can never be assigned or have its value changed (similar to `const`). | ||
|
||
By default, all class members are `public` but you can apply other data modifiers like `private` and `protected` to control member visibility. Protected members are only visible to subclasses of the class they're declared in. Private is like Protected but doesn't allow access to the member even from subclasses. | ||
|
||
In general, it is considered good practice in coding to use the minimal visibility required. For example, if you never plan to write to the field, you should start with `readonly`. If you find that you need to write to the field, but only in the code in the class, you should use `private`. Usage of `protected` is rare. In most cases, well-structured code will have most instance variables of a class as `private`. | ||
|
||
We've tried to cover the basics of Classes here. You can read a lot more in detail [on the TypeScript handbook](https://www.typescriptlang.org/docs/handbook/2/classes.html). | ||
|
||
## Generics | ||
|
||
Generics allow us to create reusable and flexible components which can work over a variety of types rather than a single one. This allows users to consume these components and use their types. | ||
|
||
```ts | ||
// Without generics | ||
function getArray(items: any[]): any[] { | ||
return new Array().concat(items); | ||
} | ||
|
||
let numArray = getArray([1, 2, 3, 4]); | ||
let strArray = getArray(["alice", "dave", "mike"]); | ||
|
||
// With generics | ||
function getArray<T>(items: T[]): T[] { | ||
return new Array().concat(items); | ||
} | ||
|
||
let numArray = getArray<number>([1, 2, 3, 4]); | ||
let strArray = getArray<string>(["alice", "dave", "mike"]); | ||
``` | ||
|
||
The drawback of using `any[]` is that something like `numArray.push('hello')` would not throw an error, but when you use generics it acts as a placeholder with types defined and applied when creating variables from the generic. | ||
|
||
You can read more about generics and considerations for using this feature of TypeScript on [The TypeScript handbook](https://www.typescriptlang.org/docs/handbook/2/generics.html). | ||
|
||
## Decorators | ||
|
||
With the introduction of Classes in TypeScript and ES6, there now exist certain scenarios that require additional features to support annotating or modifying classes and class members. Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript. | ||
|
||
A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form `@expression`, where `expression` must be a function that will be called at runtime with information about the decorated declaration. For example, given the decorator `@sealed` we might write the `sealed` function as follows: | ||
|
||
```ts | ||
function sealed(target) { | ||
// do something with 'target' ... | ||
} | ||
``` | ||
|
||
You can read more about Decorators in detail [on the TypeScript handbook](https://www.typescriptlang.org/docs/handbook/decorators.html). You will most likely not use this in everyday projects as it is a very experimental feature, so we have only paraphrased the basics from the handbook and made you aware of the existence of this advanced type. | ||
|
||
## Conclusion | ||
|
||
Now we have taken a look at basic everyday types as well as complex advanced types. Were you able to visualize how these types being applied could help in reducing bugs in our code? Slowly you will start to get the hang of TypeScript with more practice. Let us now explore how the TypeScript compiler works in the next lesson. | ||
|
||
--- | ||
|
||
## References | ||
|
||
- https://www.youtube.com/watch?v=BCg4U1FzODs&ab_channel=TraversyMedia | ||
- https://www.typescriptlang.org/docs/handbook/2/classes.html | ||
- https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces | ||
- https://www.typescriptlang.org/docs/handbook/2/generics.html | ||
- https://www.typescriptlang.org/docs/handbook/decorators.html | ||
- https://gist.github.com/bradtraversy/f80a4cd87e7034bea5264f7d8c431b4e |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# TypeScript Compiler | ||
|
||
Now that we know so much about what TypeScript syntax looks like, we will learn about the TypeScript compiler. The objectives of this lesson are: | ||
|
||
1. Installing and using the TypeScript compiler | ||
2. Viewing compiled JS output for TS code | ||
3. Understanding the configuration and use of the compiler config file | ||
|
||
## What is a compiler? | ||
|
||
In case you haven't heard about "compilers" before or are unsure about the term, A compiler is a special program that translates a programming language's source code into machine code, bytecode, or another programming language. The source code is typically written in a high-level, human-readable language such as Java or C++. A programmer writes the source code in a code editor or an integrated development environment (IDE) that includes an editor, saving the source code to one or more text files. A compiler that supports the source programming language reads the files, analyzes the code, and translates it into a format suitable for the target platform. | ||
|
||
Sometimes the term "transpiler" is used interchangeably with compiler, but they are not exactly the same. Transpilers, or source-to-source compilers, are tools that read the sourcecode written in one programming language and produce the equivalent code in another programming language with a similar level of abstraction. And TypeScript is a good example of a transpiler as it converts TypeScript code to JavaScript. Similarly, Babel transpiler can also be used for converting the ES6 JS code to ES5 JS sourcecode. Compilers also convert the code from one language to another language but both languages are very different in abstraction level. For example, Java compiler converts the `.java` file to `.class` file. | ||
|
||
Strictly speaking, TypeScript is _transpiled_ to JavaScript. However, most developers and Microsoft itself refer to the tool that does this as "TypeScript Compiler". That said, don't fret too much about the loose usage of the terms compiler and compilation. As long as what's actually happening is clear from the context, it doesn't really matter which term is used — the message still gets through. Transpilers are also called source-to-source compilers, so "TypeScript Compiler" could also be considered short for "TypeScript to JavaScript Compiler". | ||
|
||
## Installing and using the compiler | ||
|
||
To install and start using the TypeScript Compiler or `tsc` on your machine, you can do a global npm package installation. | ||
|
||
```bash | ||
npm i -g typescript | ||
``` | ||
|
||
Then you can verify the installation by checking for the compiler version. | ||
|
||
```bash | ||
tsc -v | ||
``` | ||
|
||
Now you can start writing TypeScript code in any `.ts` file. Let's say you wrote some code in a file called `index.ts`. All you need to do to compile to JavaScript is: | ||
|
||
```bash | ||
tsc index | ||
``` | ||
|
||
You will see that TypeScript creates a JS file of the same name `index.js` with the transpiled JS code. If there were any errors found during compilation, they would get flagged in the terminal. But if you're using a modern editor like VSCode, you can find errors being flagged by the IDE itself and even auto-complete recommendations showing up to prevent you from making type errors. | ||
|
||
You can open up the transpiled JS file and read through the code. Depending on how complex your TS file was or how many lines of code it had, the transpiled JS file may or may not be easily readable. But just a skim through the generated JS files still gives an idea of how the TypeScript Compiler works. | ||
|
||
You can also simply run the command `tsc` if you have more than one target TS file to be compiled and it will automatically search for TS files in the project folder and transpile them. You can also run TypeScript Compiler in watch mode using `tsc --watch` and it will watch for file changes, re-compile and hot reload. | ||
|
||
## TypeScript Compiler Configuration | ||
|
||
TypeScript uses a configuration file in the project folder to follow any custom rules or options you would like to set. To generate this file, just run: | ||
|
||
```bash | ||
tsc --init | ||
``` | ||
|
||
This will immediately create a `tsconfig.json` file in your project folder. You'll see that this file contains a property called `compilerOptions` with lots and lots of options mostly commented out. You can read through the comments or visit the TypeScript docs to learn about these options, but no need to worry about memorizing these. In most of your projects, you might have to adjust just a few properties here and there. | ||
|
||
```json | ||
{ | ||
"compilerOptions": { | ||
"module": "commonjs", | ||
"esModuleInterop": true, | ||
"target": "es6", | ||
"noImplicitAny": true, | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"outDir": "dist", | ||
"baseUrl": ".", | ||
"paths": { | ||
"*": ["node_modules/*"] | ||
} | ||
}, | ||
"include": ["src/**/*"] | ||
} | ||
``` | ||
|
||
For example, you might see the `target` property is set by default to `"es5"`. This results in `var` being used in the output JS files. You may change this to `"es6"` to enable use of `let` and `const` and other ES6 syntax features. | ||
|
||
You can configure the `outDir` and `rootDir` properties and provide paths to your desired output directory and input directory. So then you could have a `src` directory and a `dist` directory in your project structure to separate source code and production code. | ||
|
||
## Conclusion | ||
|
||
You can read more about the `tsconfig.json` file [here](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) but it is really not that complicated. This lesson intends to give you an idea about how the TypeScript compiler works and you can possibly visualize a little bit of what is happening under the hood. You can also find many online TypeScript IDEs, playgrounds, and compilers that let you try out TS code and view the compiled JS output, [here](https://www.codingrooms.com/compiler/typescript) is one. We will now move into looking at TypeScript in practice with Node and Express. | ||
|
||
--- | ||
|
||
## References | ||
|
||
- https://www.techtarget.com/whatis/definition/compiler | ||
- https://howtodoinjava.com/typescript/transpiler-vs-compiler/ | ||
- https://www.youtube.com/watch?v=BCg4U1FzODs&t=669s&ab_channel=TraversyMedia |
Oops, something went wrong.