Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

05.10 Computed properties

Výuka

Proč computed properties?

Computed properties (vypočítané vlastnosti) umožňují použít výraz jako klíč objektu. Místo statického názvu můžeš klíč vypočítat za běhu programu.

Proč to potřebujeme?

  • Dynamické klíče - Vytvoř klíče na základě proměnných
  • Programatické objekty - Generuj objekty z dat
  • Flexibilita - Klíč závisí na podmínkách nebo vstupech
  • Kratší kód - Vytvoř objekt v jednom kroku

Představ si to jako: Popisky na krabicích ve skladu. Místo předem vytištěných štítků (statické klíče) můžeš štítky tisknout podle toho, co zrovna potřebuješ (computed properties) - "Box-" + číslo,datum, nebo cokoliv jiného.

Jak to funguje?

Computed properties:
1. Syntaxe: { [výraz]: hodnota }
2. Výraz v hranatých závorkách se vyhodnotí
3. Výsledek se použije jako klíč
4. Můžeš použít proměnné, volání funkcí, operace
5. ES6 feature

Klíčové koncepty

  • Computed property - { [expr]: value }
  • Dynamický klíč - klíč vypočítaný za běhu
  • Výraz - cokoliv, co vrací string (nebo symbol)
  • ES6 feature - od ES2015
  • Kombinace s metodami - { [getName()]() {...} }

JavaScript

Příklad 1: Základní computed property

// Klasický způsob - statický klíč
const obj1 = {
  name: 'Alice'
};

// Computed property - dynamický klíč
const key = 'name';
const obj2 = {
  [key]: 'Bob'  // [key] se vyhodnotí jako 'name'
};

console.log(obj2);
// → { name: 'Bob' }

// Můžeš použít výrazy
const prefix = 'user';
const id = 123;

const user = {
  [prefix + 'Id']: id,           // → userId: 123
  [prefix + 'Name']: 'Charlie',  // → userName: 'Charlie'
  [prefix + 'Age']: 30           // → userAge: 30
};

console.log(user);
// → { userId: 123, userName: 'Charlie', userAge: 30 }

Co se stalo?

  • [výraz] - vyhodnotí výraz a použije jako klíč
  • Můžeš použít proměnné, concatenation, volání funkcí
  • Klíč je dynamický - závisí na hodnotě výrazu

Příklad 2: Computed properties s funkcemi

function getFieldName(type) {
  return `${type}Value`;
}

const data = {
  [getFieldName('text')]: 'Hello',     // → textValue: 'Hello'
  [getFieldName('number')]: 42,        // → numberValue: 42
  [getFieldName('boolean')]: true      // → booleanValue: true
};

console.log(data);
// → { textValue: 'Hello', numberValue: 42, booleanValue: true }

// Praktický příklad - generování klíčů
const fields = ['name', 'email', 'phone'];

const formData = fields.reduce((obj, field) => {
  obj[field + 'Error'] = null;  // Klasický způsob
  return obj;
}, {});

console.log(formData);
// → { nameError: null, emailError: null, phoneError: null }

// Nebo s computed properties přímo
const formData2 = {
  [fields[0] + 'Error']: null,
  [fields[1] + 'Error']: null,
  [fields[2] + 'Error']: null
};

Co se stalo?

  • Volání funkce v computed property: [getFieldName('text')]
  • Funkce vrátí string, který se použije jako klíč
  • Užitečné pro generování klíčů

Příklad 3: Vytvoření objektu z pole

const keys = ['a', 'b', 'c'];
const values = [1, 2, 3];

// Klasický způsob
const obj1 = {};
keys.forEach((key, index) => {
  obj1[key] = values[index];
});

console.log(obj1);
// → { a: 1, b: 2, c: 3 }

// S computed properties + reduce
const obj2 = keys.reduce((acc, key, index) => {
  return {
    ...acc,
    [key]: values[index]
  };
}, {});

console.log(obj2);
// → { a: 1, b: 2, c: 3 }

// Nebo Object.fromEntries (nejčistší)
const obj3 = Object.fromEntries(
  keys.map((key, index) => [key, values[index]])
);

console.log(obj3);
// → { a: 1, b: 2, c: 3 }

Co se stalo?

  • Computed properties v reduce - dynamicky vytváříme klíče
  • Object.fromEntries - nejčistší řešení pro tento pattern
  • Užitečné pro programatické vytváření objektů

Příklad 4: Computed properties s metodami

const actionType = 'USER';

const actions = {
  [actionType + '_LOGIN']: function() {
    return 'User logging in';
  },

  [actionType + '_LOGOUT']() {  // Method shorthand
    return 'User logging out';
  },

  // S arrow funkcí
  [actionType + '_UPDATE']: () => {
    return 'User updating';
  }
};

console.log(actions.USER_LOGIN());
// → User logging in

console.log(actions.USER_LOGOUT());
// → User logging out

console.log(actions.USER_UPDATE());
// → User updating

// Praktický příklad - event handlers
const eventType = 'click';
const element = 'button';

const handlers = {
  [eventType + element.charAt(0).toUpperCase() + element.slice(1)]() {
    console.log('Button clicked!');
  }
};

handlers.clickButton();
// → Button clicked!

Co se stalo?

  • Computed properties pro metody - dynamické názvy metod
  • Můžeš kombinovat s method shorthand nebo arrow funkcí
  • Užitečné pro event handlers, action creators

Příklad 5: Computed properties s Symbol

// Symbol jako klíč
const uniqueId = Symbol('id');
const nameSymbol = Symbol('name');

const user = {
  [uniqueId]: 123,
  [nameSymbol]: 'Alice',
  age: 25
};

console.log(user[uniqueId]);
// → 123

console.log(user[nameSymbol]);
// → Alice

// Symbol klíče se nezobrazují v Object.keys()
console.log(Object.keys(user));
// → ['age'] (Symboly se nezobrazují!)

// Musíš použít Object.getOwnPropertySymbols()
console.log(Object.getOwnPropertySymbols(user));
// → [Symbol(id), Symbol(name)]

// Praktické použití - private-like properties
const _private = Symbol('private');

const obj = {
  publicProp: 'visible',
  [_private]: 'hidden'
};

console.log(obj.publicProp);  // → visible
console.log(obj[_private]);   // → hidden
console.log(Object.keys(obj));  // → ['publicProp']

Co se stalo?

  • Symbol jako computed property - unikátní klíče
  • Symbol klíče nejsou enumerable - nezobrazují se v Object.keys()
  • Užitečné pro "private" vlastnosti (ne opravdu private, ale skryté)

Příklad 6: Praktický příklad - Redux actions

// Generování action types a creators
const entity = 'USER';
const operations = ['CREATE', 'READ', 'UPDATE', 'DELETE'];

// Vytvoř action types
const actionTypes = operations.reduce((types, op) => {
  return {
    ...types,
    [entity + '_' + op]: `${entity}_${op}`
  };
}, {});

console.log(actionTypes);
// → { USER_CREATE: 'USER_CREATE', USER_READ: 'USER_READ', USER_UPDATE: 'USER_UPDATE', USER_DELETE: 'USER_DELETE' }

// Vytvoř action creators
const actionCreators = operations.reduce((creators, op) => {
  return {
    ...creators,
    [op.toLowerCase() + entity.charAt(0) + entity.slice(1).toLowerCase()]: (payload) => ({
      type: actionTypes[entity + '_' + op],
      payload
    })
  };
}, {});

console.log(actionCreators.createUser({ name: 'Bob' }));
// → { type: 'USER_CREATE', payload: { name: 'Bob' } }

console.log(actionCreators.updateUser({ id: 1, name: 'Alice' }));
// → { type: 'USER_UPDATE', payload: { id: 1, name: 'Alice' } }

Co se stalo?

  • Programatické generování action types a creators
  • Computed properties pro dynamické klíče
  • Reálný use case z Redux patterns

TypeScript

TypeScript přidává typovou kontrolu computed properties.

Stejné příklady s typy

// Computed properties s typy
const key: string = 'name';

const obj: { [key: string]: string } = {
  [key]: 'Alice'
};

// Index signature
interface User {
  [key: string]: string | number;
}

const user: User = {
  name: 'Bob',
  age: 30,
  [key]: 'Charlie'
};

// Typed computed properties
type UserKey = 'name' | 'age' | 'email';

function createUser(key: UserKey, value: string | number): Record<UserKey, string | number> {
  return {
    [key]: value
  } as Record<UserKey, string | number>;
}

const user1 = createUser('name', 'David');  // ✅ OK
const user2 = createUser('age', 35);        // ✅ OK
// createUser('invalid', 'test');  // ❌ Error: Argument of type '"invalid"' is not assignable to parameter of type 'UserKey'

// Mapped types
type UserRecord = Record<'name' | 'age' | 'email', string>;

const user3: UserRecord = {
  name: 'Eve',
  age: '28',
  email: 'eve@example.com'
};

// Generic computed properties
function createObject<K extends string, V>(key: K, value: V): Record<K, V> {
  return { [key]: value } as Record<K, V>;
}

const obj1 = createObject('name', 'Frank');  // Record<'name', string>
const obj2 = createObject('age', 40);        // Record<'age', number>

// Const assertion with computed properties
const prefix = 'user' as const;

const userData = {
  [prefix + 'Id']: 123,
  [prefix + 'Name']: 'George'
} as const;
// TypeScript inferuje: { userID: 123, userName: 'George' }

TypeScript přidává:

  • Typovou kontrolu klíčů - musí odpovídat index signature
  • Record<K, V> - typ pro objekty s computed properties
  • Mapped types - transformace typů
  • Prevenci chyb - upozorní na neplatné klíče

Rozdíl JS vs TS

JavaScript:

  • Computed properties fungují bez typové kontroly
  • Můžeš vytvořit jakýkoliv klíč
  • Flexibilnější, ale nebezpečnější

TypeScript:

  • Computed properties mají typovou kontrolu
  • Index signature nebo Record<K, V> definují platné klíče
  • Bezpečnější, prevence chyb
// JavaScript - projde
const key = 'randomKey';
const obj = {
  [key]: 'value'
};

// TypeScript - kontrola
type AllowedKeys = 'name' | 'age';

// Musíš definovat index signature
interface Obj {
  [key: string]: string;
}

const obj: Obj = {
  [key]: 'value'  // ✅ OK s index signature
};

Tip

💡 Používej computed properties pro dynamické objekty:

// ✅ Vytvoř objekt z pole
const fields = ['name', 'email', 'phone'];
const errors = fields.reduce((obj, field) => ({
  ...obj,
  [field + 'Error']: null
}), {});

// Místo
const errors = {};
fields.forEach(field => {
  errors[field + 'Error'] = null;
});

💡 Kombinuj s template literals pro čitelnost:

// ✅ Čitelné computed properties
const type = 'user';
const actions = {
  [`${type}Login`]: () => {},
  [`${type}Logout`]: () => {},
  [`${type}Update`]: () => {}
};

// Místo
const actions = {
  [type + 'Login']: () => {},
  [type + 'Logout']: () => {},
  [type + 'Update']: () => {}
};

💡 Symbol pro unikátní klíče:

// ✅ Symbol klíče nejsou enumerable
const id = Symbol('id');
const user = {
  [id]: 123,
  name: 'Alice'
};

Object.keys(user);  // → ['name'] (Symbol se nezobrazí)

Kvíz

Co vypíše tento kód?

const a = 'foo';
const b = 'bar';

const obj = {
  [a + b]: 'value'
};

console.log(obj.foobar);

- - [a + b] je computed property

  • a + b = 'foo' + 'bar' = 'foobar'
  • Objekt je { foobar: 'value' }
  • obj.foobar'value'

- Vlastnost foobar existuje

- Hodnota vlastnosti je 'value', ne 'foobar'

- Kód je validní

Důležité: Computed properties vyhodnotí výraz a použijí výsledek jako klíč!

Důležité: Computed properties vyhodnotí výraz a použijí výsledek jako klíč!

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě