Last active
December 26, 2024 10:52
-
-
Save predragnikolic/248622ab5f58f3f9de34d8d1cf5d3f72 to your computer and use it in GitHub Desktop.
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
// 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 |
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
// 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 | |
} | |
} | |
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 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}` |
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
// 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