mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-04 01:05:58 +02:00
Add typescript tech spotlight
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
---
|
||||
authors:
|
||||
- "Daniell#4062"
|
||||
created_at: "2021/09/08"
|
||||
title: What is TypeScript?
|
||||
---
|
||||
|
||||
## What is TypeScript?
|
||||
|
||||
TypeScript is a programming language which adds optional static typing to JavaScript, therefore it is a strict superset. Being developed and maintained by Microsoft, the language gained a lot of interest, it's primary goal is to deal with the shortcomings of JavaScript in a non-breaking way.
|
||||
|
||||
Because TypeScript adds optional features to JavaScript, being a JavaScript developer you could use it today, the language can be gradually adopted, meaning you could add it to any existing JavaScript project and configure more strict rules as you are in the process of implementing it and getting close to fully flip the switch. Even if you have a history in typed languages you may find something of interest.
|
||||
|
||||
## Why should I use TypeScript?
|
||||
|
||||
JavaScript is a general purpose programming language, therefore, TypeScript is too. Do you want to make games, apps, api's, or websites, are you a JavaScript developer tired of seeing `TypeError: Cannot read property 'x' of undefined` every time you run your code? Continue to read about how TypeScript can greatly enhance your developer experience.
|
||||
|
||||
## Static typing
|
||||
|
||||
Because TypeScript is statically typed, errors can be catched before you run your code. Editors that utilise IntelliSense will give you warnings about possible errors that may occur as you write code, this includes, but is not limited to the error mentioned above, TypeScript can warn you about values being possibly undefined or values that don't exist, which makes refactoring a lot easier. IntelliSense will also give you autocompletion and refactoring shortcuts.
|
||||
|
||||
Let's see static typing in action. Assume a third party library provides us with the types and function below. `leftovers` are not available the moment we run this function:
|
||||
|
||||
```ts
|
||||
type Stock = {
|
||||
fruits: Fruit[]
|
||||
leftovers?: Leftover[]
|
||||
}
|
||||
|
||||
declare function getStock(): Stock
|
||||
```
|
||||
|
||||
When we run this code in JavaScript:
|
||||
|
||||
```ts
|
||||
const stock = getStock()
|
||||
stock.leftovers.forEach(leftover => console.log(leftover))
|
||||
// Cannot read property 'leftovers' of undefined
|
||||
```
|
||||
|
||||
We lost millions because of this bug :(. You might be wondering how TypeScript could have saved us here:
|
||||
|
||||
```ts
|
||||
const stock = getStock()
|
||||
// leftovers?: Leftover[] | undefined
|
||||
// Object is possibly 'undefined'.(2532)
|
||||
stock.leftovers.forEach(leftover => console.log(leftover))
|
||||
```
|
||||
|
||||
Our editor warns us as we code! We would also not be able to transpile this code to JavaScript before we fix it by either using optional chaining `stock.leftovers?.forEach(...` , or by writing an if statement which checks for the existence of `leftovers` before using it.
|
||||
|
||||
## Backwards compatibility
|
||||
|
||||
TypeScript transpiles to JavaScript so it can be used in any environment that supports JavaScript. Deno (https://deno.land/) can run TypeScript in runtime. The native TypeScript Checker (tsc) can be used to transpile your code using modern ECMAScript features to work with older versions if needed, alternatively Babel (https://babeljs.io/) can be used for transpiling. We no longer need to worry about our code not being compatible with older browsers or servers with a legacy Node.js versions!
|
||||
|
||||
## How do I use TypeScript?
|
||||
|
||||
Please check your editor's requirements to configure TypeScript language features, Microsoft's [Visual Studio Code](https://code.visualstudio.com/) ships with TypeScript natively.
|
||||
|
||||
The commands below assume you have Node.js installed, if you have not installed it yet, see:
|
||||
|
||||
Node.js for Windows https://nodejs.org/en/
|
||||
NVM For Windows https://github.com/coreybutler/nvm-windows
|
||||
|
||||
Node Version Manager for macOS / Linux https://github.com/nvm-sh/nvm: This prevents you from having to use sudo / deal with other permission errors and allows you to change Node.js version easily compared to installing Node.js through your package manager.
|
||||
|
||||
```bash
|
||||
# Initialise an empty project in the current folder
|
||||
npm init -y
|
||||
# Install TypeScript as dev dependency
|
||||
npm install --save-dev typescript
|
||||
# Generate a tsconfig.json file, this file contains our TypeScript project info
|
||||
npx --no-install tsc --init
|
||||
```
|
||||
|
||||
You can now create a `index.ts` file and start writing TypeScript inside!
|
||||
|
||||
## Some helpful scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "nodemon --transpile-only src/index.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These scripts go inside your `package.json` file generated by `npm init` and can be invoked by running the following commands:
|
||||
|
||||
**npm run build**: This runs TypeScript's type checker and transpiles your TypeScript files to JavaScript using the options provided in `tsconfig.json`.
|
||||
|
||||
**npm start**: This runs your TypeScript entry file in watch mode (restarts your project when you save), the `transpile-only` flag tells ts-node to skip type checking, this makes reloading much faster and it is also safe because our editor warns us about type errors already and so does the TypeScript type checker when running our build script.
|
||||
|
||||
The start script mentioned, requires you to install 2 additional dependencies:
|
||||
|
||||
```bash
|
||||
npm install --save-dev nodemon ts-node
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enough talking, let me see the code!
|
||||
|
||||
TypeScript provides an additional layer of documentation. Type annotations make it clear to developers how code is supposed to be used.
|
||||
|
||||
## Type annotations
|
||||
|
||||
```ts
|
||||
function add(a: number, b: number) {
|
||||
return a + b
|
||||
}
|
||||
```
|
||||
|
||||
## Class access modifiers
|
||||
|
||||
```ts
|
||||
class Person {
|
||||
protected name: string
|
||||
private age: number
|
||||
readonly numberOfLives = 1
|
||||
public favouriteLanguage: string
|
||||
|
||||
constructor(name: string, age: number, favouriteLanguage = "TypeScript") {
|
||||
this.name = name
|
||||
this.age = age
|
||||
this.favouriteLanguage = favouriteLanguage
|
||||
}
|
||||
|
||||
@CatchErrorAndLog // Did you know that TypeScript also supports decorators?
|
||||
public someMethod() {
|
||||
throw new Error("method not implemented")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generic types
|
||||
|
||||
Generics are a powerful tool, they give you the ability to create reusable components that work with a wide variety of types rather than a single one, you might have heard of them if you are familiar with C# or Java.
|
||||
|
||||
Let's say we want to create a function which accepts an object and a key of that object in order to to return the value that maps to it's key, how do we dynamically determine which keys are valid without creating a function for every possible object shape in the world? We introduce generics:
|
||||
|
||||
```ts
|
||||
const member = {
|
||||
username: "moe",
|
||||
isShid: true,
|
||||
}
|
||||
|
||||
function getValueByKey<T, K extends keyof T>(obj: T, key: K): T[K] {
|
||||
return obj[key]
|
||||
}
|
||||
|
||||
getValueByKey(member, "username") // string
|
||||
getValueByKey(member, "isShid") // boolean
|
||||
```
|
||||
|
||||
This function accepts 2 generic parameters (you could think of them as placeholders): `T` and `K`, we assign the first parameter of this function to generic type T, you might be wondering about the `extends` keyword, basically this adds a constraint to generic parameter `K`, you could read it as "Type `K` must be a key of type `T`".
|
||||
|
||||
Finally we declare the return type by indexing type `T` using our second parameter which is the key, this is referred to as a "indexed access type". TypeScript will now warn us whenever we provide a key that does not exist in the object. We achieved type safety without knowing what object the user would pass in to our function.
|
||||
|
||||
To make sure we only accept objects for our first parameter, we could give type `T` a constraint as well using the `Record` utility type (which happens to accept generic parameters as well): `T extends Record<string, unknown>`, this way we are saying "Type `T` must be a value which type is assignable to an object (record) with any strings for it's keys, and it has unknown values", which is essentially any object to us, the creators of this function.
|
||||
|
||||
## Conditional types
|
||||
|
||||
What if we want to create a function or compose other types based on certain criteria? This is where we can make use of conditional types:
|
||||
|
||||
```ts
|
||||
// Conditional types uses the same syntax you know of ternaries
|
||||
type IsNumber<T> = T extends number ? true : false
|
||||
type Result = IsNumber<7> // true
|
||||
|
||||
// Inferring typed within conditional types using the "infer" keyword.
|
||||
// This example uses variadic tuple types
|
||||
type LastElementType<T> = T extends [...infer _Head, infer Tail] ? Tail : never
|
||||
type Last = LastElementType<[string, boolean, number]> // number
|
||||
```
|
||||
|
||||
## Other examples
|
||||
|
||||
```ts
|
||||
// Template literal types
|
||||
type Border = `border-${"top" | "bottom" | "left" | "right"}`
|
||||
|
||||
// Narrowing down union types
|
||||
type APIResponseSuccess = {
|
||||
status: 200;
|
||||
body: string;
|
||||
};
|
||||
|
||||
type APIResponseAuthFailed = {
|
||||
status: 401;
|
||||
body: string;
|
||||
errorMessage: string;
|
||||
};
|
||||
|
||||
type APIResponseAuthNotFound = {
|
||||
status: 404;
|
||||
};
|
||||
|
||||
type APIResponse =
|
||||
| APIResponseSuccess
|
||||
| APIResponseAuthFailed
|
||||
| APIResponseAuthNotFound;
|
||||
|
||||
function handleResponse(response: APIResponse) {
|
||||
if (response.status === 200) {
|
||||
return console.log(response.body);
|
||||
}
|
||||
|
||||
if (response.status === 401) {
|
||||
return console.log(response.errorMessage);
|
||||
}
|
||||
|
||||
console.log("Not found");
|
||||
}
|
||||
|
||||
// Utility types, this example uses the `Partial` utility type
|
||||
interface Todo {
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
|
||||
return { ...todo, ...fieldsToUpdate };
|
||||
}
|
||||
|
||||
const todo1 = {
|
||||
title: "organize desk",
|
||||
description: "clear clutter",
|
||||
};
|
||||
|
||||
const todo2 = updateTodo(todo1, {
|
||||
description: "throw out trash",
|
||||
});
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
TypeScript Documentation: https://www.typescriptlang.org/docs/
|
||||
TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/intro.html: Starting point for anyone who wants to learn TypeScript.
|
||||
Playground: https://www.typescriptlang.org/play: Try TypeScript in your browser!
|
||||
|
||||
## Books
|
||||
typescript-book: https://github.com/basarat/typescript-book: Free online guide to TypeScript.
|
||||
Programming TypeScript: https://www.oreilly.com/library/view/programming-typescript/9781492037644/: Solid book for beginners.
|
||||
Effective TypeScript: https://effectivetypescript.com/: Improve your use of TypeScript (best for experienced programmers).
|
||||
Tackling TypeScript: https://exploringjs.com/tackling-ts/index.html: Adopt TypeScript as a JavaScript programmer.
|
||||
|
||||
## Videos
|
||||
Courses on egghead.io: https://egghead.io/q/typescript
|
||||
Reference in New Issue
Block a user