Time to combine all the knowledge from this module into one project! You'll build a typed cosmic dashboard that uses:
The cosmic dashboard consists of several sections:
1// Base interface
2interface SpaceEntity {
3 id: string;
4 name: string;
5 discoveredYear: number;
6}
7
8// Discriminated union - different object types
9interface PlanetEntity extends SpaceEntity {
10 kind: "planet";
11 radius: number;
12 habitable: boolean;
13}
14
15interface StarEntity extends SpaceEntity {
16 kind: "star";
17 temperature: number;
18 spectralClass: "O" | "B" | "A" | "F" | "G" | "K" | "M";
19}
20
21interface AsteroidEntity extends SpaceEntity {
22 kind: "asteroid";
23 diameter: number;
24 composition: string;
25}
26
27type CosmicObject = PlanetEntity | StarEntity | AsteroidEntity;
28
29// Dashboard state
30interface DashboardState {
31 objects: CosmicObject[];
32 filter: CosmicObject["kind"] | "all";
33 searchQuery: string;
34}1// Generic table component with full typing
2interface Column<T> {
3 key: keyof T;
4 label: string;
5 render?: (value: T[keyof T], item: T) => React.ReactNode;
6}
7
8interface DataTableProps<T extends { id: string }> {
9 data: T[];
10 columns: Column<T>[];
11 onRowClick?: (item: T) => void;
12}
13
14function DataTable<T extends { id: string }>({
15 data, columns, onRowClick
16}: DataTableProps<T>) {
17 return (
18 <table>
19 <thead>
20 <tr>
21 {columns.map(col => (
22 <th key={String(col.key)}>{col.label}</th>
23 ))}
24 </tr>
25 </thead>
26 <tbody>
27 {data.map(item => (
28 <tr key={item.id} onClick={() => onRowClick?.(item)}>
29 {columns.map(col => (
30 <td key={String(col.key)}>
31 {col.render
32 ? col.render(item[col.key], item)
33 : String(item[col.key])}
34 </td>
35 ))}
36 </tr>
37 ))}
38 </tbody>
39 </table>
40 );
41}1type NewObjectForm =
2 | { kind: "planet"; name: string; radius: string; habitable: boolean }
3 | { kind: "star"; name: string; temperature: string; spectralClass: string }
4 | { kind: "asteroid"; name: string; diameter: string; composition: string };
5
6function AddObjectForm({ onAdd }: { onAdd: (obj: CosmicObject) => void }) {
7 const [kind, setKind] = useState<CosmicObject["kind"]>("planet");
8 const [name, setName] = useState("");
9
10 const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
11 e.preventDefault();
12 // Creates the appropriate object based on the selected type
13 const id = crypto.randomUUID();
14 const year = new Date().getFullYear();
15
16 // ... object creation logic
17 };
18
19 return (
20 <form onSubmit={handleSubmit}>
21 <select
22 value={kind}
23 onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
24 setKind(e.target.value as CosmicObject["kind"])
25 }
26 >
27 <option value="planet">Planet</option>
28 <option value="star">Star</option>
29 <option value="asteroid">Asteroid</option>
30 </select>
31 <input value={name} onChange={e => setName(e.target.value)} />
32 <button type="submit">Add</button>
33 </form>
34 );
35}Below you'll find the complete implementation of the cosmic dashboard with full TypeScript typing. Analyze the code, modify it, and experiment with types!