Skip to content

RN Lezione 17: TypeScript per Pythonisti

  • 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

TypeScript = JavaScript + tipi. È un superset di JavaScript sviluppato da Microsoft.

JavaScript: let nome = "Mario"; // OK sempre
TypeScript: let nome: string = "Mario"; // specifico il tipo
// JavaScript — scopri l'errore SOLO a runtime
function saluta(nome) {
return `Ciao ${nome.toUpperCase()}`;
}
saluta(42); // ❌ ERRORE a runtime: 42.toUpperCase is not a function
// TypeScript — errore IMMEDIATO in editor
function saluta(nome: string) {
return `Ciao ${nome.toUpperCase()}`;
}
saluta(42); // ❌ ERRORE in editor: "Argument of type 'number' is not assignable to parameter of type 'string'"
# 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 hintsTypeScript
Obbligatorio?❌ No, solo documentazione✅ Sì (di default)
Controllato quando?Mai (a runtime)Alla scrittura (in editor)
Serve a?DocumentarePrevenire errori

Se crei un nuovo progetto Expo oggi, è già TypeScript:

Terminal window
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:

Terminal window
mv App.js App.tsx
npx expo start # Expo installa TypeScript automaticamente!
{
"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.


// Tipi primitivi (sempre minuscoli!)
const nome: string = "Mario";
const eta: number = 17; // interi e decimali sono number
const 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 è string
const anno = 2026; // TypeScript sa che è number

Non serve sempre scrivere il tipo — TypeScript lo capisce da solo:

// ❌ Ridondante — TS lo sa già
const nome: string = "Mario";
// ✅ Meglio — TS inferisce string
const nome = "Mario";
// ✅ Necessario — se non c'è valore iniziale
let indirizzo: string;

// Due sintassi equivalenti:
const numeri: number[] = [1, 2, 3];
const numeri2: Array<number> = [1, 2, 3]; // sintassi generics
// Array misti
const misto: (string | number)[] = ["Mario", 17, "Roma", 42];
// ↑ tipo unione: string OPPURE number
// Array di oggetti
type Studente = {
nome: string;
eta: number;
};
const studenti: Studente[] = [
{ nome: "Mario", eta: 17 },
{ nome: "Sofia", eta: 16 },
];

// 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;
}
// Uso
const studente: Studente = {
nome: "Mario",
eta: 17,
// classe è opzionale, non serve!
};

Differenza pratica: type si usa di più in React per props e stati semplici. interface è meglio per librerie e OOP. In React Native vedrai più spesso type.

type Status = "attivo" | "inattivo" | "sospeso";
// ↑ solo questi 3 valori possibili!
const stato: Status = "attivo"; // ✅
const stato2: Status = "boh"; // ❌ ERRORE: non è nei valori
type Callback = (id: number) => void;
// ↑ parametro ↑ non restituisce nulla
const eliminaUtente: Callback = (id) => {
console.log(`Elimino utente ${id}`);
};

Il pattern principale: definisci un type per le props

Section titled “Il pattern principale: definisci un type per le props”
// ❌ JavaScript — nessun controllo
const Card = ({ titolo, prezzo }) => {
return (
<View>
<Text>{titolo}</Text>
<Text>€ {prezzo}</Text>
</View>
);
};
// ✅ TypeScript — props tipizzate
type 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>
);
};
// ✅ 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} />
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>
);
};

// TypeScript INFERISCE il tipo dal valore iniziale
const [count, setCount] = useState(0);
// count: number ✅
const [nome, setNome] = useState("");
// nome: string ✅
// Se l'iniziale è null, devi specificare
const [utente, setUtente] = useState<Utente | null>(null);
// utente: Utente | null
const [items, setItems] = useState<Prodotto[]>([]);
// items: Prodotto[] ✅

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();
}, []);
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();
}, []);

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()}
/>
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 ricevuti
type 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 tipizzati
router.push({
pathname: "/dettaglio",
params: { id: "5", nome: "Pizza", prezzo: "6.50" }
});

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: strnome: string
eta: inteta: 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 { ... }

🎯 Esercizio: “Converti in TypeScript”

Section titled “🎯 Esercizio: “Converti in TypeScript””

Prendi il componente JavaScript qui sotto e convertilo in TypeScript:

// DA CONVERTIRE IN TYPESCRIPT
const 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}
/>
);
}
  1. type Prodotto per la struttura dati
  2. CardProdottoProps per le props del componente
  3. App con stato useState<Prodotto[]>(...)
  4. keyExtractor con tipo corretto