Created
August 9, 2021 13:56
-
-
Save justcoder1/c46e590af2570aec65e2004a6bbf15a1 to your computer and use it in GitHub Desktop.
TS-Types
This file contains hidden or 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
# Type Basics | |
### Type declaration | |
There are several ways we can declare type in TS | |
ts | |
let word: string = "test"; | |
let num: number = 101; | |
let words: string[] = ["this", "is", "an", "array", "of", "strings"]; | |
let nums: number[] = [1, 2, 3, 4]; | |
let bools: boolean[] = [true, false]; | |
This is explicit Type Annotation, which let TS know the variable you have declared is going to be of a certain type, | |
we can also declare types and annotate variables with those types, this is _Type Aliasing_. | |
ts | |
type Num = number; | |
let num: Num = 10; | |
The purpose of this becomes clearer when you consider that these types can be unions of types ... | |
ts | |
type NumOrString = number | string; | |
let data = "test"; | |
data = 0; | |
Our intention is that data should only be a `number` or a `string` and TS will allow us to reassign data to either. | |
### typing _shape_ | |
Explicit type annotation and type aliasing can also be used to type objects, when we do this we generally refer to the type as the _shape_ of the object. | |
ts | |
const person: { name: string; age: number; codes: boolean } = { | |
name: "Jim", | |
age: 32, | |
codes: true, | |
}; | |
// could also be typed as ... | |
type Person = { name: string; age: number; codes: boolean }; | |
const otherPerson: Person = { name: "Alex", age: 30, codes: true }; | |
### Unions and Intersections | |
Unions `|` and Intersections `&` for some types work exactly how you would expect, in the previous example it was a Union of string and number, however when combining complex type aliases it does nto function as 'or' but as a Union of the two types | |
ts | |
type Dog = { legs: 4; name: string; tail: true; fur: true }; | |
type Fish = { fins: number; name: string; tail: true; scales: boolean }; | |
type FishOrDog = Fish | Dog; | |
const ohMy: FishorDog = { | |
legs: 4, | |
name: "billy", | |
tail: true, | |
fins: 4, | |
scales: true, | |
}; | |
This is a union of the two types, it complies with the structure of `Fish` but is also able to have the attributes of a `Dog`, in order to satisfy Typescripts type checker the declared object must fulfil at least the criteria for one of the unioned types. | |
Intersections of types require all the criteria that are in both types to satisfy the type check. | |
ts | |
type Dog = { legs: 4; name: string; tail: true; fur: true }; | |
type Fish = { fins: number; name: string; tail: true; scales: boolean }; | |
type FishAndDog = Fish & Dog; | |
const fishDog: FishAndDog = { | |
name: "billy", | |
tail: true, | |
fins: 4, | |
scales: true, | |
legs: 4, | |
fur: true, | |
}; | |
In order to truly understand how TypeScript behaves, we have to appreciate that types are related to one another | |
... | |
## Type Hierarchy | |
Take a look at the image below, this shows typescript will check wether or not a type satisfies its typecheck. This also follow how we understand some of how JS works, is an `Array` an `Object` yes, is a `function` also yes. | |
 | |
Note the type `Any` sitting at the top of this list, `Any` can be .... anything except unknown. Why do we not just use any for all our definitions, because any can be anything it make ts behave like regular JS would and totally prevents the type checker from working. | |
ts | |
const name: any = "Jim"; | |
name.pizza(); | |
So where is an appropriate use for `any` .... as a very, very, VERY last resort if you are unable to type something, avoid `any` wherever possible as it invalidates the hard work that we have put into type-ing our code. | |
## Functions | |
functions need to have their parameters and their return values typed | |
ts | |
function add(a:number b:number):number{ | |
return a+b | |
} | |
function isGreaterThan50(n:number):boolean{ | |
return n > 50 | |
} | |
function countChars(str:string, char:string):number{ | |
let count:number = 0 | |
for (let i:number= 0; i < str.length; i++ ){ | |
const shouldCount: boolean = str[i] === char | |
if(shouldCount)count++ | |
} | |
return count | |
} | |
## Call Signatures | |
Call signatures is a way for us to be able to type functions we have seen that you are able to type the params directly, you can also type the return values directly, but we can also type the whole function as a type alias | |
ts | |
type Add = (a: number, b: number) => number; | |
const add: Add = (a, b) => { | |
return a + b; | |
}; | |
we can only type alias function expressions, note: you no longer need to type the params as its noted in the signatures and ts will take their types from the signature. | |
## Index Signatures | |
Index signatures enable us to dynamically add key/value pairs to objects. The way the type checker reads this is, given an object all keys of type T must have values of type U | |
ts | |
type EmailLookup = { | |
[name: string]: string; | |
}; | |
const lookUp: EmailLookup = { | |
jim: "[email protected]", | |
alex: "[email protected]", | |
}; | |
## Type Inference | |
Having types everywhere can make you code feel quite cluttered, TS will also infer types for us in many circumstances, it can infer the types of declared variables and even function return values: | |
ts | |
let name: 'Jim' //infers type string | |
const pi: 3.14 //when declaring a const will infer the variable is exactly 3.14 | |
const person = { | |
name: 'jim' | |
age: 33, | |
lovesToCode: true | |
} | |
// {name: string, age: number,lovesToCode: boolean} | |
//this will infer the return value of the function to be a boolean. | |
function hasAccess(person:{accessLevel:number}){ | |
return person.accessLevel > 2 | |
} | |
## Type Level vs Value Level | |
Type level code can be described as the code that typescript is interacting with to ensure that the actions we take are TypeSafe, typescript asks does the value that you are giving conform to the type you have described | |
ts | |
let password: string = "Password"; | |
The part after the colon in the variable declaration is the layer of typescript that we are adding, and typescript is checking if the value (in this case `'Password'`) conforms to the type defined, which it does | |
When we go to use said variable later typescript will check that any method or properties can be called or accessed on that type. | |
ts | |
//... | |
password.apples; // should show a TS error | |
password.toUpperCase(); // should be fine | |
The Type checking doesn't mind what the value of the variable is, other than that it conforms to `string` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment