/ Gists

Gists

On gists

Utility type: Readonly

Typescript

index.ts #

/*
Readonly je utility typ v TypeScriptu, 
který změní všechny vlastnosti daného typu na pouze pro čtení (readonly)

Readonly<T>
*/

// 1
interface User {
    id: number;
    name: string;
    email: string;
}

const user: Readonly<User> = {
    id: 1,
    name: 'Alice',
    email: 'alice@example.com',
};

// Pokus o změnu vlastnosti způsobí chybu
user.name = 'Bob'; // Error: Cannot assign to 'name' because it is a read-only property.

// 2
interface Config {
    apiEndpoint: string;
    timeout: number;
}

const config: Readonly<Config> = {
    apiEndpoint: 'https://api.example.com',
    timeout: 3000,
};

// Tento pokus o úpravu způsobí chybu:
config.timeout = 5000; // Error: Cannot assign to 'timeout' because it is a read-only property.

On gists

Utility type: Required

Typescript

index.ts #

/*
Required je utility typ v TypeScriptu, který změní všechny vlastnosti daného typu na povinné (required).
*/

interface User1 {
    id: number;
    name?: string;
    email?: string;
}

type RequiredUser = Required<User1>;

const user1: RequiredUser = {
    id: 1,
    name: 'Alice',
    email: 'alice@example.com',
};

On gists

Utility type: Partial

Typescript

index.ts #

// union
type StringOrNumber = string | number;

// intersection
type User = { id: number };
type Admin = { isAdmin: boolean };
type AdminUser = User & Admin; // { id: number; isAdmin: boolean; }

// return type
type GetUserType = () => { id: number; name: string };
type UserType = ReturnType<GetUserType>; // { id: number; name: string }

// return type pres interface
interface StringFormat {
    (str: string, isUpper: boolean): string;
}

let format: StringFormat;

format = function (str: string, isUpper: boolean) {
    return isUpper ? str.toLocaleUpperCase() : str.toLocaleLowerCase();
};

console.log(format('hi', true));

On gists

Utility type: Pick

Typescript

index.ts #

/*
Pick:

Pick<T, K> je utility typ v TypeScriptu, který vytváří nový typ výběrem určitých vlastností K z typu T.
Používá se pro vytvoření podmnožiny existujícího typu.
*/

// 1
interface User {
    id: number;
    name: string;
    email: string;
    phone: number;
}

type UserInfo = Pick<User, 'id' | 'name'>;
type UserBasicInfo = Pick<User, 'name' | 'email'>;

const user: UserInfo = {
    id: 1,
    name: 'abc',
};

const userDetails: UserBasicInfo = {
    name: 'abc',
    email: 'abc@gmail.com',
};

interface TestedPerson {
    name: string;
    age: number;
    address: string;
    email: string;
    phone: string;
}

// 2 Kombinace Pick s jinými utility typy
type OptionalPersonBasicInfo = Partial<Pick<TestedPerson, 'name' | 'age'>>;

const partialBasicInfo: OptionalPersonBasicInfo = {
    name: 'Bob',
    // age může být vynecháno
};

// 3 Použití Pick s vnořenými objekty
interface ComplexPerson {
    name: string;
    age: number;
    address: {
        street: string;
        city: string;
        country: string;
    };
}

type PersonNameAndCity = Pick<ComplexPerson, 'name'> & Pick<ComplexPerson['address'], 'city'>;

const nameAndCity: PersonNameAndCity = {
    name: 'Charlie',
    city: 'New York',
};

On gists

Utility type: Record

Typescript

index.ts #

/*
Record<Keys, Type>
Keys může být string, number, symbol nebo union těchto typů.
Type může být jakýkoli typ.

Kdy Record využít
Když chcete zajistit, aby objekt měl přesnou strukturu s předem definovanými typy klíčů a hodnot.
Pokud například potřebujete typově bezpečně definovat mapování mezi hodnotami (např. slovníky nebo konfigurace).
*/

const scores: Record<string, number> = {
    Alice: 10,
    Bob: 20,
    Charlie: 30,
};

type Person = 'name' | 'age' | 'email';
const personInfo: Record<Person, string> = {
    name: 'Alice',
    age: '30',
    email: 'alice@example.com',
};

type Task = {
    title: string;
    completed: boolean;
};
type ProjectTasks = Record<string, Task>;
const projectStatus: ProjectTasks = {
    'Task 1': { title: 'Design UI', completed: true },
    'Task 2': { title: 'Implement backend', completed: false },
    'Task 3': { title: 'Write tests', completed: false },
};

On gists

Responsive CSS Grids (autoheight by viewport)

CSS trick

style.css #

/*
  Demo: https://jsbin.com/hugodahuge/1/edit?html,css,output
*/

.grid {
  display: grid;
  grid-template-rows: repeat(4, 1fr); 
  grid-auto-columns: calc((100vh - 3em) / 4);
  grid-auto-flow: column;
  grid-gap: 1em;
  height: 100vh;
}

.grid-item:nth-child(3n) {
  background-color: gray;
}

.grid-item:nth-child(3n + 1) {
  background-color: green;
}

.grid-item:nth-child(3n + 2) {
  background-color: yellow;
}

On gists

Optimize Complex Conditionals in JavaScript

JavaScript

index.js #

// https://blog.stackademic.com/how-to-optimize-complex-conditionals-in-javascript-0fcaf0add82a


const onButtonClick = (status) => {
  if (status == 1) {
    jumpTo('Index Page');
  } else if (status == 2 || status == 3) {
    jumpTo('Failure Page');
  } else if (status == 4) {
    jumpTo('Success Page');
  } else if (status == 5) {
    jumpTo('Cancel Page');
  } else {
    jumpTo('Other Actions');
  }
};

// 1
// if => switch

const onButtonClick = (status) => {
  switch (status) {
    case 1:
      jumpTo('Index Page');
      break;
    case 2:
    case 3:
      jumpTo('Failure Page');
      break;
    case 4:
      jumpTo('Success Page');
      break;
    case 5:
      jumpTo('Cancel Page');
      break;
    default:
      jumpTo('Other Actions');
  }
};


// ------------------------------------------


const onButtonClick = (status, identity) => {
  if (identity == 'guest') {
    if (status == 1) {
      // logic for guest status 1
    } else if (status == 2) {
      // logic for guest status 2
    }
    // Additional logic for other statuses...
  } else if (identity == 'master') {
    if (status == 1) {
      // logic for master status 1
    }
    // Additional logic for other statuses...
  }
};


// 2
// interesting solution ;)
// nested if to map with keys where key mean concaten ifs..

const actions = new Map([
  ['guest_1', () => { /* logic for guest status 1 */ }],
  ['guest_2', () => { /* logic for guest status 2 */ }],
  ['master_1', () => { /* logic for master status 1 */ }],
  ['master_2', () => { /* logic for master status 2 */ }],
  ['default', () => { /* default logic */ }],
]);

const onButtonClick = (identity, status) => {
  const action = actions.get(`${identity}_${status}`) || actions.get('default');
  action();
};




// 3
// object with keys instead of use of ifs
const actions = {
  '1': 'Index Page',
  '2': 'Failure Page',
  '3': 'Failure Page',
  '4': 'Success Page',
  '5': 'Cancel Page',
  'default': 'Other Actions',
};

const onButtonClick = (status) => {
  const action = actions[status] || actions['default'];
  jumpTo(action);
};

On gists

example.js

example.js #

_

On gists

Promise / Promise.withResolvers

JavaScript

example.js #

const { promise, resolve, reject } = Promise.withResolvers();

setTimeout(() => resolve('Done!'), 1000);
promise.then(console.log); // 'Done!'



function foo()
{
  const {promise, resolve, reject} = Promise.withResolvers()

  setTimeout(() => {
    resolve('DONE')
  }, 2000)
  
  
  return promise
}


function foo2()
{
  const {promise, resolve, reject} = withResolvers()

  setTimeout(() => {
    resolve('DONE 2')
  }, 2500)
  
  
  return promise
}

// polyfill
function withResolvers() {
  let resolve, reject;
  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  return { promise, resolve, reject };
}

// Použití:
const { promise: aliasOnlyForTesting, resolve } = withResolvers();



(async() => {
  const data = await foo()
  console.log(data)
  
  const data2 = await foo2()
  console.log(data2)
})()

On gists

Awaited computed from composable - special pattern by me

Vue.js

useAnyComposable.js #

// 1 - composable
import { ref, computed, watchEffect } from 'vue';
import useSomeOtherComposable from './useSomeOtherComposable';

export default function useMyComposable() {
  const { asyncValue1, asyncValue2 } = useSomeOtherComposable();

  const resolved = ref(false);

  // Hodnoty, které vrátíme, až budou splněny podmínky
  const computedValue1 = ref(null);
  const computedValue2 = ref(null);

  // Proměnná promise, která se splní, když budou data připravena
  const dataReady = new Promise((resolve) => {
    watchEffect(() => {
      if (asyncValue1.value === 'desiredValue1' && asyncValue2.value === 'desiredValue2') {
        computedValue1.value = asyncValue1.value;
        computedValue2.value = asyncValue2.value;
        resolved.value = true;
        resolve();
      }
    });
  });


 /*
  // i watchEffect lze zastavit
  
      const dataReady = new Promise((resolve) => {
      const stopEffect = watchEffect(() => {
        if (asyncValue1.value === 'desiredValue1' && asyncValue2.value === 'desiredValue2') {
          computedValue1.value = asyncValue1.value;
          computedValue2.value = asyncValue2.value;
          resolve(); // Vyřeší Promise, když jsou hodnoty požadované
          stopEffect(); // Zastaví watchEffect, protože už není potřeba
        }
      });
    });
 
 */



  // Vrátíme computed hodnoty i promise
  return {
    computedValue1,
    computedValue2,
    dataReady,
    resolved
  };
}

// usage - component
import { defineComponent, onMounted } from 'vue';
import useMyComposable from './useMyComposable'; // another composable which returns computed

export default defineComponent({
  setup() {
    const { computedValue1, computedValue2, dataReady } = useMyComposable();

    onMounted(async () => {
      await dataReady; // Počkáme, až budou hodnoty připravené
      console.log('Values are ready:', computedValue1.value, computedValue2.value);
    });

    return {
      computedValue1,
      computedValue2
    };
  }
});


// 2 - watch insteadof watchEffect
import { ref, watch } from 'vue';
import useSomeOtherComposable from './useSomeOtherComposable';

export default function useMyComposable() {
  const { asyncValue1, asyncValue2 } = useSomeOtherComposable();

  const computedValue1 = ref(null);
  const computedValue2 = ref(null);

  const dataReady = new Promise((resolve) => {
    const stopWatching = watch(
      [asyncValue1, asyncValue2],
      ([newVal1, newVal2]) => {
        if (newVal1 === 'desiredValue1' && newVal2 === 'desiredValue2') {
          computedValue1.value = newVal1;
          computedValue2.value = newVal2;
          resolve(); // Vyřeší Promise, jakmile hodnoty odpovídají požadavkům
          stopWatching(); // Zastaví sledování, protože už není potřeba
        }
      },
      { immediate: true } // Sleduj hned od začátku
    );
  });

  return {
    computedValue1,
    computedValue2,
    dataReady
  };
}


// component usage
import { defineComponent, onMounted } from 'vue';
import useMyComposable from './useMyComposable';

export default defineComponent({
  setup() {
    const { computedValue1, computedValue2, dataReady } = useMyComposable();

    onMounted(async () => {
      await dataReady; // Počkáme, až budou hodnoty připravené
      console.log('Values are ready:', computedValue1.value, computedValue2.value);
    });

    return {
      computedValue1,
      computedValue2
    };
  }
});


// ---------------------------------------------------
// geolocation checker aka MSP 
// ---------------------------------------------------
import { ref, computed } from 'vue';
import { useMyComposable } from './path/to/composable';

export default {
  setup() {
    // Definuj proměnné na úrovni komponenty
    const computedValue1 = ref(null);
    const computedValue2 = ref(null);
    const dataReady = ref(false);

    const check = () => {
      const { computedValue1: cv1, computedValue2: cv2, dataReady: dr } = useMyComposable();
      
      // Přiřaď hodnoty z composable do definovaných proměnných
      computedValue1.value = cv1.value;
      computedValue2.value = cv2.value;
      dataReady.value = dr.value;
    };

    // Spusť funkci nebo ji použij, když potřebuješ načíst data
    check();

    // Můžeš nyní přistupovat k computedValue1 a computedValue2 přímo mimo `check`
    console.log(computedValue1.value, computedValue2.value);

    return {
      computedValue1,
      computedValue2,
      dataReady,
      check,
    };
  },
};