Skip to content

Instantly share code, notes, and snippets.

@predragnikolic
Last active December 26, 2024 10:52
Show Gist options
  • Save predragnikolic/248622ab5f58f3f9de34d8d1cf5d3f72 to your computer and use it in GitHub Desktop.
Save predragnikolic/248622ab5f58f3f9de34d8d1cf5d3f72 to your computer and use it in GitHub Desktop.
// IF STATEMENTS
//
// Пример 1 - typeof
function getStringOrNumber(): string | number {
return Math.random() > 0.5 ? "jedan" : 1
}
const input = getStringOrNumber()
if (typeof input === "string") {
input // ...
} else {
input // ...
}
input // ...
// Пример 2 instanceof
function getArrayOfNumbersOrNumber(): number[] | number {
return Math.random() > 0.5 ? [5, 2, 1, 9] : 4
}
const input2 = getArrayOfNumbersOrNumber()
if (input2 instanceof Array) {
input2 // ...
}
// Пример 3 built in type-guard functions
if (Array.isArray(input2)) {
input2 // ...
}
// Пример 4 "property_name" in object
function getName(): { name: string } | { error: { message: string } } {
return { name: "Марина" }
}
const input3 = getName()
if ("error" in input3) {
input3 // ...
} else {
input3 // ...
}
// Шта није уреду?
// function getName2(): {name: string} | string {
// return {name: 'Марина'}
// }
// const input4 = getName2()
// if (typeof input4 === 'object' && 'name' in input4) {
// input4 // ...
// } else {
// input4 // ...
// }
// Шта није уреду?
// function getName3(): {name: string} | null {
// return {name: 'Марина'}
// }
// const input5 = getName3()
// if (input5 !== null && 'name' in input5) {
// input3 // ...
// } else {
// input3 // ...
// }
// # DISCRIMINATED UNIONS
type Response2 =
| { status: 200; data: { name: string } }
| { status: 301; to: string }
| { status: 400; error: Error }
function _handleResponse(response: Response2) {
if (response.status === 200) {
response.data
} else if (response.status === 301) {
response.to
} else {
response.error
}
switch (response.status) {
case 200:
return response.data
case 301:
return response.to
default:
return response.error
}
}
// Шта се деси када додамо нови објекат `{status: 500}`?
// Шта није уреду?
// type Response =
// | { status: 200; data: { name: string } }
// | { status: 301; to: string }
// | { status: 400; error: Error }
// Додај ово да се typescript не буни.
// export const foo = 21
// TYPE GUARDS
type SuccessResponse = { status: 200; data: { name: string } }
type RedirectResponse = { status: 301; to: string }
type ErrorResponse = { status: 400; error: Error }
type Response3 = SuccessResponse | RedirectResponse | ErrorResponse
function isSuccessResponse(value: any): value is SuccessResponse {
return value.status === 200
}
function isErrorResponse(staGod: any): staGod is ErrorResponse {
return staGod.status === 400
}
function _handleResponse2(response: any) {
// уместо
if (response.status === 200 ) {
response.data
}
// можемо да напишемо
if (isSuccessResponse(response)) {
response.data
}
if (isErrorResponse(response)) {
response.error
}
}
// ASSERTION FUNCTIONS
function assertSuccessResponse(value: Response3): asserts value is SuccessResponse {
if (value.status !== 200) throw new Error("Није SuccessResponse")
}
function assertErrorResponse(staGod: Response3): asserts staGod is ErrorResponse {
if (staGod.status !== 400) throw new Error("Није ErrorResponse")
}
function _handleResponse3(response: Response3) {
response // ...
assertSuccessResponse(response)
response
assertErrorResponse(response)
response
}
function _handleResponse4(response: Response3) {
response // ...
assertErrorResponse(response)
response
}
// Assignment Arrays
let firstName = "hello"
type FirstName = typeof firstName
const lastName = "hello"
type LastName = typeof lastName
const directions = ["LEFT", "RIGHT", "UP", "DOWN"]
type Direction = "LEFT" | "RIGHT" | "UP" | "DOWN"
const direction: Direction[] = ["LEFT", "RIGHT", "UP", "DOWN"]
// пример `as const`
const direction2 = ["LEFT", "RIGHT", "UP", "DOWN"]
type Direction2 = typeof direction2
// Assignment Objects
const obj = {
firstName: "Marina",
lastName: "Andjelkovic",
age: 29,
} as const
type ObjectType = typeof obj
// const variabla: TIP = vrednost
// function fn(parametar: TIP): TIP {}
//
// const variabla = vrednost
// function fn(parametar: TIP) {}
// built in primitives
const boolExample: boolean = false
const stringExample: string = "name"
const numberExample: number = 2
const undefinedExample: undefined = undefined
const nullExample: null = null
let anyExample: any = false
const unknownExample: unknown = 21
const voidExample: () => void = () => {
return 21
}
// const voidExample: () => undefined = () => {
// return 21
// }
let voidExampleResult = voidExample()
function infiniteLoop1(): never {
while (true) {}
}
function neverExample() {
let x = 1
infiniteLoop1()
return x + 1
}
// AVOID
// Object, String, Number, Boolean
// let x: Boolean = ...
// let x: String = ...
// ...
// Типови могу да се мешају
let stringOrNumber: string | number = "21"
stringOrNumber = 23
// built in JS Objects
function builtIn(
date: Date,
error: Error,
someArray: Array<string>,
map: Map<string | number, number>,
set: Set<string>,
somePromise: Promise<string>,
) {
date.toISOString()
error.message
someArray[0].charAt(1)
map.get("string")
map.get(21)
// map.get(false) // this will show a type error
set.add("dsa")
// set.add(21) // this will show a type error
somePromise.then((value) => value)
}
// define a async function
function someApi(): Promise<string> {
return Promise.resolve("hello")
}
// Што се буни?
async function foo() {
const result = await someApi()
return result
}
type A = {
name: string
age: number
}
const objekat: A = {name: 'Milan', age: 12}
type B = (arg: number) => string
const fn: B = (arg) => 'This is ' + arg.toString()
// Овако се дефинише низ.
const niz: Array<string> = ["hello"]
// или овако
const niz2: string[] = ["hello"]
const niz3: (string | number)[] = ["hello", 2, 3]
// или овако
const niz4: Array<string | number> = ["hello", 2, 3]
// Common Syntax
interface MyResponse {
statusCode: number
}
interface HTTPAble {
payloadSize: number
}
interface JsonResponse extends MyResponse, HTTPAble {
version: number
outOfStock?: boolean
update: (retryTimes: number) =>void
update2(retryTimes: number): void // другачија синтакса
(): string
new (): number
// [key: string]: number
readonly body: string
}
function handleJson(json: JsonResponse) {
json//.
let x1 = json()
let x2 = new json()
let x3 = json.thisDoesntExist // одкоментариши [key: string]: number и види шта ће се десити
json.body = 21
}
// Generic
interface Api<T> {
data: T
}
function first(items: any[]): any {
return items[0]
}
let a = first(['prvi', 'drugi'])
a.charAt(1)
let b = first([1, 2])
b.toFixed()
function firstInArray<T>(array: T[]): T {
return array[0]
}
let a1 = firstInArray([1,2,3])
let a2 = firstInArray(['2das','dsad'])
let a3 = firstInArray(['2das',1])
let a4 = firstInArrayBestTypeSafety(['2das',1])
let a5 = firstInArrayBestTypeSafety([1, 'dasda'])
function firstInArrayBestTypeSafety<T>(array: [T, ...any[]]): T {
return array[0]
}
// Function Overload
interface Expect {
(matcher: string, age: number): boolean
(matcher: string): string
}
function example(overload: Expect) {
let r = overload('false', 21)
let r1 = overload('hello')
}
// Get & Set
interface RulerInitial {
size: number | string
}
// The problem
function rulerExample1(r: RulerInitial) {
let size = r.size
r.size = '20'
r.size = 21
}
// The solution
interface Ruler {
get size(): number
set size(value: string| number)
}
function rulerExample2(r: Ruler) {
let size = r.size
r.size = '20'
r.size = 21
r.size = false
}
// Extension via merging
function interfaceMergingExample(p: Person) {
p.
}
interface Person {
name: string
}
interface Person {
age: number
}
interface CanCalculateArea {
area(): number
}
class Square implements CanCalculateArea {
private a: number
area(): number {
return this.a * this.a
}
}
// Type Aliases
// Type vs Interface
// Интерфејс може да опише само структуру објекта
// Док Type, поред објеката, може и да опише и друге врсет типова као на пример string, number...
interface MyResponse {
statusCode: number
}
// Primitive type
type SanatizedInput = string
type Money = number
type MissingNo = 404
// Union type
type Direction = "left" | "right"
// Object Literal type
type MyResponseType = {
statusCode: number
}
type Responses = MyResponseType[]
// tuple type
type TupleExample = [string, number]
let osobe: TupleExample[] = [
["данила", 29],
["Предраг", 29],
]
// named tuple example
type NamedTupleExample = [ime: string, age: number]
// Интерфејси могу да се прошире тако што
interface ExtendInterface {
a: number
}
interface ExtendInterface {
b: string
}
// Док типови могу да се прошире, и то се зове "Intersection types"
type Extend1Type = {
a: number
}
type Extend2Type = {
b: string
}
type Extend3Type = Extend1Type & Extend2Type
// Разлика 3, typescript може да typecheck-ује интерфејсе далеко брже него type.
// Дефиниција typa има исти скопе као и JS вариаблa
type A = number
function foo() {
type A = string
let a: A = 21
}
let a: A = "21"
// TS долази са Utility Types који су већ уграђени
// Овде су наведени сви
// https://www.typescriptlang.org/docs/handbook/utility-types.html
// ево пар примера
interface Todo {
title: string
description: string
}
// Partial<T>
type PartialTodo = Partial<Todo>
// Partial<T, key of T>
type PickTodo = Pick<Todo, "title">
// Omit<T, key of T>
type OmitTodo = Omit<Todo, "title">
// Record<keyType, valueType>
const recordPrimer: Record<string, number> = {
hello: 21,
hello2: 21,
}
const recordPrimer2: Record<Direction, MyResponse> = {
left: { statusCode: 213 },
right: { statusCode: 213 },
}
async function bar(): Promise<string> {
return Promise.resolve("Hello")
}
// ReturnType<typeof Function>
type BarReturn = ReturnType<typeof bar>
// Awaited<T>
type UwrappedPromise = Awaited<BarReturn>
// Object literal syntax
type JsonResponse = {
version: number
outOfStock?: boolean
data: {
person: {
name: string
age: string
}
}
update: (retryTimes: number) => void
update2(retryTimes: number): void // другачија синтакса
(): string
new (): number
// [key: string]: number
readonly body: string
}
// Type Indexing
type Person = JsonResponse["data"]["person"]
// type from value
const book = {
title: "Изокренута прича",
author: "Бранко Ћопић",
}
type Book = object //... TODO како да извичемо book тип
// type from return function
function baz(): number {
return 21
}
type bazReturn = number // TODO како да извичемо baz повратни тип
// Мapperd Types
type Artist = {
name: string
age: number
}
// Увод за keyof
type ArtistKeys = keyof Artist
let key: ArtistKeys = "asdf"
type Sybscriber<T> = {
[Nesto in keyof T]: (value: T[Nesto]) => void
}
type ArtistSub = Sybscriber<Artist>
const sub: ArtistSub = {
name(value) {
console.log(value)
},
age(value) {
console.log(value)
},
}
// Conditional Types
type Bird = { legs: 2 }
type Dog = { legs: 4 }
type Ant = { legs: 6 }
type Wolf = { legs: 4 }
type Animals = Bird | Dog | Ant | Wolf
// type HasFourLegs<T> = T extends {legs: 4} ? T : never
type FourLegs = Animals extends { legs: 4 } ? Animals : never
// template union types
type langs = "sr" | "en"
type footerLocaleIds = "header" | "footer"
type AllLocaleIds = "sr_header" | "sr_footer" | "en_header" | "en_footer"
// type AllLocaleIds = `${langs}_${footerLocaleIds}`
// Class
class ABC {}
const abc = new ABC()
// `private x` vs #private
class Bag {
private item: any
}
class BagJsPrivateField {
#item: any
}
// other TS fields
class TSFields {
item4: any // Public by default
public item3: any
protected item2: any
private item: any
}
// `this` in classes
// Binding issues:
class User {
name: string
constructor(name: string) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
const user = new User("John")
// This works
user.sayHi(); // displays an alert with "John"
//
// but this doesn't work
const user1 = new User("John");
const sayHi1 = user.sayHi;
sayHi1(); // displays an alert with "undefined"
class UserBindThis {
name: string
constructor(name: string) {
this.name = name;
this.sayHi = this.sayHi.bind(this);
}
sayHi() {
alert(this.name);
}
}
// this should work now
const user2 = new UserBindThis("John");
const sayHi2 = user2.sayHi;
sayHi2(); // displays an alert with "undefined"
class UserUseArrowFunctionToBindThis {
name: string
constructor(name: string) {
this.name = name;
// this.sayHi = this.sayHi.bind(this);
}
sayHi = () => {
alert(this.name)
}
}
const user3 = new UserUseArrowFunctionToBindThis("John");
const sayHi3 = user3.sayHi;
sayHi3(); // displays an alert with "undefined"
// Type and Value
const a: Bag = new Bag()
// ^^^ type ^^^ value
// Be careful NOT to do this
class C implements Bag {}
// Common Syntax
class Account {
id: string
constructor(id: string) {
this.id = id
}
}
interface HasName {
name: string
}
interface HasAge {
age: number
}
class UserAccount extends Account implements HasName, HasAge {
age: number
name: string
email: string
displayName?: boolean
money!: number // ! каже typesceipt-y "веруј ми, ово постоји",
#attributes: Map<any, any>
roles = ["user"]
readonly createdAt = new Date()
constructor(id: string, email: string) {
super(id)
this.email =email
}
setName(name: string) {
this.name =name
}
verifyName = (name: string) =>{
// ...
}
get accountId() {
return this.id
}
set accountId(value: string | number) {
this.id = String(value)
}
private makeRequest() {
//...
}
protected handleRequest() {
//...
}
static #userCount = 0
static registerUser(user: UserAccount) {
//...
}
}
// Generics
class Box<T> {
content: T
constructor(value: T) {
this.content = value
}
}
const stringBox = new Box('a package')
// Parameter properties
// usually yoy would type
class Locate {
public x: number
public y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
}
// but you can just do this in TS
class LocateShortSyntax {
constructor(public x: number, public y: number) {}
}
// Abstract Class
abstract class Animal {
abstract getName(): string
printName() {
console.log('Hello,', this.getName())
}
}
class Dog extends Animal {
getName(): string {
return "Кики"
}
}
// Decorators
// Ретко кад ћеш ти писати декораторе тренутно. Једино ако ти то желиш.
// Декораторе обично користе библиотеке:
// https://lit.dev/
// https://stenciljs.com/
// https://typeorm.io/entities#what-is-entity
// Ако те занимају декоратори баци поглед на https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#decorators
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment