###### Table of Contents - [[#Basic Types]] - [[#Literal Types]] - [[#Arrays]] - [[#Generic Arrays]] - [[#Tuples]] - [[#Unions]] - [[#Enums]] - [[#Objects]] - [[#Type Assertion]] - [[#Functions]] - [[#Return type inference]] - [[#Interfaces]] - [[#Interfaces with Functions]] - [[#Interfaces with Classes]] - [[#Types vs Interfaces]] - [[#Generics]] ^dc20dd - [[#With React]] - [[#More info]] To set up TypeScript in a project (creates a `tsconfig.json` file) ```zsh tsc --init ``` ### Syntax errors vs type errors In JavaScript, any code with valid _syntax_ will run. In TypeScript, code must have valid _syntax_ and must _type check_. Only then will it run. - JavaScript: syntax check ➞ execution. - TypeScript: syntax check ➞ type check ➞ execution. There are three categories of types in Typescript:  - **`Built-in`** types include number, string, boolean, undefined, null, and void. - **`User-defined`** types include enum, array, interface, class, and tuple. - the **`any`**  type is a superset of all Typescript data types, and it is the loosest one available. It means that a variable can be of any type. Type checking is overridden when this type is used. ### Basic Types ```typescript let id: number = 5 let company: string = 'ACME Corporation' let isPublished: boolean = true let x: any = 'Hello' ``` ### Literal Types In addition to basic types like `number` and `string`, every concrete number and every concrete string is also a type. For example, a variable of type `1` can only hold the number `1`. It can't hold `2`; that's a compile-time type error. ```typescript let one: 1 = 1; one; //➞ 1 let one: 1 = 2; one; //➞ type error: Type '2' is not assignable to type '1'. ``` These are called _literal types_. For example, the type `1` above is a _literal number type_. We can combine _literal types_ with _unions_ to allow only certain values. This seems like a strange feature at first, and most statically typed programming languages don't support it. However, it's very useful in practice and is used often in real-world TypeScript code. ```typescript let oneOrTwo: 1 | 2 = 2; oneOrTwo //➞ 2 let oneOrTwo: 1 | 2 = 3; oneOrTwo //➞ type error: Type '3' is not assignable to type '1 | 2'. type DatabaseType = 'mysql' | 'postgres' | 'oracle'; let dbType: DatabaseType = 'mysql'; dbType //➞ 'mysql' ``` `true` and `false` are also literal types. A variable of type `true` can never be `false`. ```typescript let t: true = true; t //➞ true ``` ### Arrays ```typescript let ids: number[] = [1, 2, 3] let arr: any[] = [1, true, 'Hello'] ``` #### Generic Arrays In addition to array types written as `number[]`, there's another way to write them: `Array<number>`. This syntax with angle brackets (`<` and `>`) shows up a lot in TypeScript. The `number[]` form only exists because many people find it more readable. An array is an array regardless of which way we write it. ```typescript let numbers: number[] = [1]; let numbers2: Array<number> = numbers; numbers2 //➞ [1] ``` Array types like `Array<number>` are an example of [[#Generics | generics]]. We can think of `Array` as a type with a "hole" in it. An array of numbers, `Array<number>`, fills the hole with the `number` type. An array of strings, `Array<string>`, fills the hole with the `string` type. ### Tuples TypeScript supports tuples, which are arrays of fixed length. For example, `[number, number]` is a tuple of two numbers. It must be exactly two numbers; not one and not three. If the length doesn't match, it's a type error. ```typescript let numbers: [number, number] = [1, 2]; numbers[0] //➞ 1 let person: [number, string, boolean] = [1, 'John', true] person[1] //➞ 'John' ``` ```typescript let numbers: [number, number] = [1]; // type error: Type '[number]' is not assignable to type '[number, number]'. Source has 1 element(s) but target requires 2. ``` Tuples can have different types in each index. This is different from arrays, where every element must have the same type. ```typescript let numberAndString: [number, string] = [1, 'a']; numberAndString[1] //➞ 'a' ``` ##### Tuple Array ```typescript // Tuple Array let employee: [number, string][] employee = [ [1, 'John'], [2, 'George'], [3, 'Ringo'], [4, 'Paul'] ] ``` ### Unions ```typescript // Allow a variable to hold more than one type let pid: string | number pid = '20' pid = 'twenty' ``` Many JavaScript functions take arguments that can be one of multiple types. That example below might seem a bit strange. We can see that `cleveland` returns `44106`, which is a number. But we explicitly told the compiler that the function returns a `string | number`. The compiler doesn't try to find a "better" type than the one we provided. It only checks against the provided type: ```typescript function getClevelandZipCode(): string | number { return 44106; } let zip: number = getClevelandZipCode(); zip; //➞ type error: Type 'string | number' is not assignable to type 'number'.Type 'string' is not assignable to type 'number'. ``` ### Enums ```typescript // Allow for the creation of named constants enum Direction1 { Up, Down, Left, Right } console.log(Direction.Up) //➞ 0 enum Direction1 { Up = 1, Down, Left, Right } console.log(Direction1.Down) //➞ 2 enum Direction2 { Up = 'Up', Down = 'Down', Left = 'Left', Right = 'Right' } console.log(Direction2.Down) //➞ 'Down' ``` ### Objects ```typescript const user: { id: number, name: string } = { id: 1, name: 'John' } // code above looks a little messy, so an alternative is to do: type User = { id: number; name: string; } const user: User = { id: 1, name: 'John' } const users: Users[] = [] // define an array of products ``` ### Type Assertion ```typescript // type assertion explicity tells the compiler we want to treat an entity as a different type let cid: any = 1 //two different syntaxes let customerId = <number>cid // or let customerId = cid as number ``` ### Functions ```typescript function addNum(x: number, y: number): number { return x + y } console.log(addNum(1, 2)) //➞ 3 function log(message: string | number): void { console.log(message) } log('Hello') //➞ 'Hello' ``` #### Return type inference Functions' return types can be inferred, which saves us from typing them out. As with all inference, the types still exist and are still enforced. Inference only means that the compiler can determine the types for us. ```typescript function two() { return 1 + 1; } two() //➞ 2 ``` ### Interfaces ```typescript interface UserInterface { // readonly property readonly id: number, name: string, // optional property age?: number } const user1: UserInterface = { id: 1, name: 'John' } ``` #### Interfaces with Functions ```typescript // interfaces with functions 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 ``` #### Interfaces with Classes ```typescript // interfaces with classes 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() { return `${this.name} is now registered.` } } const brad = new Person(1, 'Brad Jones') const mike = new Person(1, 'Mike Jordan') console.log(brad.register) //➞ `Brad Jones is now registered` // Subclass class Employee extends Person { position: string constructor(id: number, name: string, position: string) { super(id, name) this.position = position } } const emp = new Employee(3, 'Shawn', 'Developer') console.log(emp.name) //➞ 'Shawn' console.log(emp.register()) //➞ 'Shawn is now registered' ``` #### Types vs Interfaces One of the key differences between an interface definition and a type definition is that *we cannot add new properties to a type, while an interface, on the other hand, can be extendable*. Also, unlike an interface, the type alias can be used for other types, such as primitives, while an *interface declaration is always an object*. ```typescript // types can be used with primitives and with unions type Point = number | string const p1: Point = 1 // you can't use an interface in that 👆🏾 way ``` ### Generics ```typescript // Generics are used to build reusable components // <T> is a placeholder function getArray<T>(items: T[]): T[] { } // the type is defined here (in the angle brackets) let numArray = getArray<number>([1, 2, 3, 4]) let strArry = getArray<string>(['brad', 'john', 'derek']) ``` #### Generic Arrays Array types like `Array<number>` are an example of _generics_. We can think of `Array`as a type with a "hole" in it. An array of numbers, `Array<number>`, fills the hole with the `number` type. An array of strings, `Array<string>`, fills the hole with the `string` type. There's nothing special about arrays of numbers or arrays of strings. We can put any type in the hole, with no restrictions whatsoever. ```typescript let numbers: number[] = [1]; let numbers2: Array<number> = numbers; numbers2 //➞ [1] let numbers: Array<number> = [1]; let numbers2: number[] = numbers; numbers2 //➞ [1] ``` The array elements can be complex, as in arrays of arrays. This is the same array of arrays concept that you see in JavaScript. We're just writing its type down explicitly. ```typescript let arrays: Array<Array<number>> = [[1, 2], [3, 4]]; arrays[1] //➞ [3, 4] ``` ### With React ```jsx // Header.tsx export interface Props { title: string color?: string } const Header = (props: Props) => { return ( <header> <h1 style={{ color: props.color }}>{props.title}</h1> </header> ) } // App.tsx import Header from './Header' function App() { return ( <div className='App'> <Header title='Hello World' color='red' /> </div> ) } ``` ### More info [TypeScript Crash Course - Traversy](https://youtu.be/BCg4U1FzODs) [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) ___ **Tags**: #typescript