RN Lezione 17: TypeScript per Pythonisti
Obiettivi
Section titled “Obiettivi”- Capire cos’è TypeScript e perché usarlo
- Tipizzare variabili, funzioni, array e oggetti
- Usare interfacce per props dei componenti
- Convertire un progetto da JS a TS
1. Cos’è TypeScript?
Section titled “1. Cos’è TypeScript?”TypeScript = JavaScript + tipi. È un superset di JavaScript sviluppato da Microsoft.
JavaScript: let nome = "Mario"; // OK sempreTypeScript: let nome: string = "Mario"; // specifico il tipoPerché TypeScript?
Section titled “Perché TypeScript?”// JavaScript — scopri l'errore SOLO a runtimefunction saluta(nome) { return `Ciao ${nome.toUpperCase()}`;}saluta(42); // ❌ ERRORE a runtime: 42.toUpperCase is not a function// TypeScript — errore IMMEDIATO in editorfunction saluta(nome: string) { return `Ciao ${nome.toUpperCase()}`;}saluta(42); // ❌ ERRORE in editor: "Argument of type 'number' is not assignable to parameter of type 'string'"Analogia con Python
Section titled “Analogia con Python”# Python (3.5+) ha i TYPE HINTS (opzionali)def saluta(nome: str) -> str: return f"Ciao {nome}"
saluta(42) # Python NON ti ferma (errore solo a runtime)// TypeScript è STRETTO (obbligatorio se configurato)function saluta(nome: string): string { return `Ciao ${nome}`;}
saluta(42); // TypeScript TI FERMA prima di eseguire| Python type hints | TypeScript | |
|---|---|---|
| Obbligatorio? | ❌ No, solo documentazione | ✅ Sì (di default) |
| Controllato quando? | Mai (a runtime) | Alla scrittura (in editor) |
| Serve a? | Documentare | Prevenire errori |
2. Setup TypeScript in Expo
Section titled “2. Setup TypeScript in Expo”Se crei un nuovo progetto Expo oggi, è già TypeScript:
npx create-expo-app@latest MiaAppTs# ↑ già tutto configurato: tsconfig.json, App.tsx, ...Se hai un progetto JavaScript esistente, basta rinominare un file da .js a .tsx:
mv App.js App.tsxnpx expo start # Expo installa TypeScript automaticamente!tsconfig.json (configurazione)
Section titled “tsconfig.json (configurazione)”{ "compilerOptions": { "strict": true, "jsx": "react-jsx", "moduleResolution": "bundler", "target": "ESNext", "module": "ESNext", "skipLibCheck": true, "baseUrl": ".", "paths": { "@/*": ["app/*"] } }, "include": ["**/*.ts", "**/*.tsx"]}
"strict": trueè la parte più importante: attiva TUTTI i controlli.
3. Tipi base
Section titled “3. Tipi base”// Tipi primitivi (sempre minuscoli!)const nome: string = "Mario";const eta: number = 17; // interi e decimali sono numberconst isStudent: boolean = true;const nulla: null = null;const nonDefinito: undefined = undefined;const qualsiasi: any = "whatever"; // ❌ EVITA any! (perde i vantaggi di TS)
// TypeScript INFERISCE il tipo automaticamente:const città = "Roma"; // TypeScript sa che è stringconst anno = 2026; // TypeScript sa che è numberType inference (inferenza)
Section titled “Type inference (inferenza)”Non serve sempre scrivere il tipo — TypeScript lo capisce da solo:
// ❌ Ridondante — TS lo sa giàconst nome: string = "Mario";
// ✅ Meglio — TS inferisce stringconst nome = "Mario";
// ✅ Necessario — se non c'è valore inizialelet indirizzo: string;4. Array
Section titled “4. Array”// Due sintassi equivalenti:const numeri: number[] = [1, 2, 3];const numeri2: Array<number> = [1, 2, 3]; // sintassi generics
// Array misticonst misto: (string | number)[] = ["Mario", 17, "Roma", 42];// ↑ tipo unione: string OPPURE number
// Array di oggettitype Studente = { nome: string; eta: number;};const studenti: Studente[] = [ { nome: "Mario", eta: 17 }, { nome: "Sofia", eta: 16 },];5. Oggetti e interfacce
Section titled “5. Oggetti e interfacce”type vs interface
Section titled “type vs interface”// Con type (più comune in React)type Studente = { nome: string; eta: number; classe?: string; // ? = opzionale};
// Con interface (equivalente)interface Studente { nome: string; eta: number; classe?: string;}
// Usoconst studente: Studente = { nome: "Mario", eta: 17, // classe è opzionale, non serve!};Differenza pratica:
typesi usa di più in React per props e stati semplici.interfaceè meglio per librerie e OOP. In React Native vedrai più spessotype.
type con unione
Section titled “type con unione”type Status = "attivo" | "inattivo" | "sospeso";// ↑ solo questi 3 valori possibili!
const stato: Status = "attivo"; // ✅const stato2: Status = "boh"; // ❌ ERRORE: non è nei valoritype con funzione
Section titled “type con funzione”type Callback = (id: number) => void;// ↑ parametro ↑ non restituisce nulla
const eliminaUtente: Callback = (id) => { console.log(`Elimino utente ${id}`);};6. Tipizzare componenti React
Section titled “6. Tipizzare componenti React”Il pattern principale: definisci un type per le props
Section titled “Il pattern principale: definisci un type per le props”// ❌ JavaScript — nessun controlloconst Card = ({ titolo, prezzo }) => { return ( <View> <Text>{titolo}</Text> <Text>€ {prezzo}</Text> </View> );};
// ✅ TypeScript — props tipizzatetype CardProps = { titolo: string; prezzo: number; disponibile?: boolean; // opzionale};
const Card = ({ titolo, prezzo, disponibile = true }: CardProps) => { return ( <View> <Text>{titolo}</Text> <Text>€ {prezzo}</Text> {disponibile && <Text>✅ Disponibile</Text>} </View> );};Uso del componente tipizzato
Section titled “Uso del componente tipizzato”// ✅ Corretto — tutti i tipi giusti<Card titolo="Pizza" prezzo={6.50} />
// ✅ Corretto — con opzionale<Card titolo="Pasta" prezzo={8.00} disponibile={false} />
// ❌ ERRORE — prezzo è number, non string<Card titolo="Pizza" prezzo="6.50" />
// ❌ ERRORE — manca titolo<Card prezzo={6.50} />Componente con children
Section titled “Componente con children”type ContainerProps = { title: string; children: React.ReactNode; // ← tipo per children};
const Container = ({ title, children }: ContainerProps) => { return ( <View> <Text style={styles.title}>{title}</Text> {children} </View> );};7. useState con TypeScript
Section titled “7. useState con TypeScript”// TypeScript INFERISCE il tipo dal valore inizialeconst [count, setCount] = useState(0);// count: number ✅
const [nome, setNome] = useState("");// nome: string ✅
// Se l'iniziale è null, devi specificareconst [utente, setUtente] = useState<Utente | null>(null);// utente: Utente | null
const [items, setItems] = useState<Prodotto[]>([]);// items: Prodotto[] ✅8. useEffect con TypeScript
Section titled “8. useEffect con TypeScript”useEffect(() => { const fetchData = async () => { const res = await fetch("https://api.esempio.com/dati"); const data: Post[] = await res.json(); // ← tipizziamo la risposta setPosts(data); }; fetchData();}, []);Tipizzare la risposta API
Section titled “Tipizzare la risposta API”type Post = { userId: number; id: number; title: string; body: string;};
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => { const fetchPosts = async () => { const res = await fetch("https://jsonplaceholder.typicode.com/posts"); const data: Post[] = await res.json(); // ← ora TS sa com'è fatto setPosts(data); }; fetchPosts();}, []);9. FlatList con TypeScript
Section titled “9. FlatList con TypeScript”type Prodotto = { id: number; nome: string; prezzo: number;};
const PRODOTTI: Prodotto[] = [ { id: 1, nome: "Pizza", prezzo: 6.50 }, { id: 2, nome: "Pasta", prezzo: 8.00 },];
// FlatList tipizzata<FlatList data={PRODOTTI} renderItem={({ item }: { item: Prodotto }) => ( <Text>{item.nome} — €{item.prezzo}</Text> )} keyExtractor={(item: Prodotto) => item.id.toString()}/>Alternativa: estrarre renderItem
Section titled “Alternativa: estrarre renderItem”const renderItem = ({ item }: { item: Prodotto }) => ( <View style={styles.card}> <Text>{item.nome}</Text> <Text>€ {item.prezzo}</Text> </View>);
<FlatList data={PRODOTTI} renderItem={renderItem} keyExtractor={(item: Prodotto) => item.id.toString()}/>10. Navigazione con TypeScript (Expo Router)
Section titled “10. Navigazione con TypeScript (Expo Router)”import { router, useLocalSearchParams } from "expo-router";
// Tipizzare i parametri ricevutitype DettaglioParams = { id: string; nome: string; prezzo: string; // i params sono sempre string!};
export default function Dettaglio() { const { id, nome, prezzo } = useLocalSearchParams<DettaglioParams>(); // ↑ ↑ tipizzati come string
const prezzoNum = Number(prezzo); // converti esplicitamente // ...}
// Navigare con parametri tipizzatirouter.push({ pathname: "/dettaglio", params: { id: "5", nome: "Pizza", prezzo: "6.50" }});11. Esempio: App completa tipizzata
Section titled “11. Esempio: App completa tipizzata”import { View, Text, FlatList, TouchableOpacity, StyleSheet } from "react-native";import { useState } from "react";import { router } from "expo-router";
// --- TIPI ---type Prodotto = { id: number; nome: string; prezzo: number; categoria: string;};
// --- DATI ---const PRODOTTI: Prodotto[] = [ { id: 1, nome: "Pizza Margherita", prezzo: 6.50, categoria: "Pizza" }, { id: 2, nome: "Pasta Carbonara", prezzo: 8.00, categoria: "Pasta" }, { id: 3, nome: "Tiramisù", prezzo: 4.00, categoria: "Dolci" },];
// --- COMPONENTE ---export default function Home() { const [prodotti] = useState<Prodotto[]>(PRODOTTI);
const renderItem = ({ item }: { item: Prodotto }) => ( <TouchableOpacity style={styles.card} onPress={() => router.push({ pathname: "/dettaglio", params: { id: String(item.id), nome: item.nome, prezzo: String(item.prezzo), } })} > <Text style={styles.nome}>{item.nome}</Text> <Text style={styles.categoria}>{item.categoria}</Text> <Text style={styles.prezzo}>€ {item.prezzo.toFixed(2)}</Text> </TouchableOpacity> );
return ( <View style={styles.container}> <FlatList data={prodotti} renderItem={renderItem} keyExtractor={(item: Prodotto) => item.id.toString()} /> </View> );}12. Tabella riassuntiva Python → TypeScript
Section titled “12. Tabella riassuntiva Python → TypeScript”| Python (type hints) | TypeScript |
|---|---|
nome: str | nome: string |
eta: int | eta: number |
voti: list[int] | voti: number[] |
info: dict[str, any] | info: Record<string, any> |
def f(x: int) -> str: | const f = (x: number): string => { } |
Optional[str] | string | null oppure string? |
Union[str, int] | string | number |
class Studente: | type Studente = { ... } o interface Studente { ... } |
13. Esercizio autonomo
Section titled “13. Esercizio autonomo”🎯 Esercizio: “Converti in TypeScript”
Section titled “🎯 Esercizio: “Converti in TypeScript””Prendi il componente JavaScript qui sotto e convertilo in TypeScript:
// DA CONVERTIRE IN TYPESCRIPTconst CardProdotto = ({ nome, prezzo, categoria, disponibile }) => { return ( <View style={styles.card}> <Text style={styles.nome}>{nome}</Text> <Text style={styles.categoria}>{categoria}</Text> <Text style={styles.prezzo}>€ {prezzo.toFixed(2)}</Text> {disponibile ? <Text style={{ color: 'green' }}>Disponibile</Text> : <Text style={{ color: 'red' }}>Non disponibile</Text> } </View> );};
export default function App() { const prodotti = [ { id: 1, nome: 'Pizza', prezzo: 6.50, categoria: 'Cibo', disponibile: true }, { id: 2, nome: 'Pasta', prezzo: 8.00, categoria: 'Cibo', disponibile: false }, ];
return ( <FlatList data={prodotti} renderItem={({ item }) => ( <CardProdotto {...item} /> )} keyExtractor={item => item.id} /> );}Cosa tipizzare
Section titled “Cosa tipizzare”type Prodottoper la struttura datiCardProdottoPropsper le props del componenteAppcon statouseState<Prodotto[]>(...)keyExtractorcon tipo corretto