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 →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
- 05.1 Vytvoření objektu
- 05.2 Vlastnosti
- 05.3 Metody objektu
- 05.4 This keyword
- 05.5 Destructuring objektů
- 05.6 Spread u objektů
- 05.7 Optional chaining
- 05.8 Nullish coalescing
- 05.9 Object.keys/values/entries
- 05.10 Computed properties
- 05.11 Getters a setters
- 05.12 Object.freeze/seal
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě