TypeGuards
Overview
TypeGuards è una classe statica di type predicates che permettono a TypeScript di fare narrowing sicuro dopo validazione runtime. Risolve il problema dell'unknown proveniente da catch (error: unknown) (TS 4.4+) e da deserializzazioni JSON, evitando crash da type assertion unsafe (as).
import { TypeGuards } from '@pzeta/postgrest'
Usata internamente da RepositoryUtils.handleError per validare la struttura ApiError prima di costruire un RestError.
API
isAxiosError(error): error is AxiosError
Verifica che un errore sia un AxiosError controllando la presenza del flag isAxiosError === true.
try {
await axios.get('/api/users')
} catch (error) {
if (TypeGuards.isAxiosError(error)) {
// TypeScript sa che error: AxiosError
console.log(error.config?.url)
console.log(error.code)
}
}
hasHttpResponse(error): error is AxiosError & { response: NonNullable<...> }
Combina isAxiosError con il check error.response !== undefined. Permette di accedere in sicurezza a status e data della response.
if (TypeGuards.hasHttpResponse(error)) {
// TypeScript: error.response: AxiosResponse (definita)
const { status, data } = error.response
console.log(`HTTP ${status}: ${JSON.stringify(data)}`)
}
Utile per distinguere errori HTTP (con response) da errori di rete (timeout, DNS failure).
hasProperty<K>(obj, prop): obj is Record<K, unknown>
Type guard per verificare la presenza di una singola proprietà su un valore unknown:
const data: unknown = JSON.parse(rawJson)
if (TypeGuards.hasProperty(data, 'name')) {
// TypeScript: data: Record<'name', unknown>
console.log(data.name) // type unknown — narrowed dopo ulteriore check
}
hasProperties<K>(obj, ...props): obj is Record<K, unknown>
Variante rest-parameter per verificare multiple proprietà contemporaneamente (AND logico):
const apiError: unknown = response.data
if (TypeGuards.hasProperties(apiError, 'code', 'message')) {
// TypeScript: apiError ha 'code' e 'message'
console.log(`${apiError.code}: ${apiError.message}`)
}
Pattern usato in handleError per validare lo shape ApiError (code + message obbligatori).
isNonEmptyString(value): value is string
Verifica che un valore sia una stringa non vuota dopo trim():
TypeGuards.isNonEmptyString('hello') // true
TypeGuards.isNonEmptyString('') // false
TypeGuards.isNonEmptyString(' ') // false (solo whitespace)
TypeGuards.isNonEmptyString(null) // false
TypeGuards.isNonEmptyString(42) // false
isValidNumber(value): value is number
Verifica che un valore sia un numero finito e non NaN:
TypeGuards.isValidNumber(42) // true
TypeGuards.isValidNumber(3.14) // true
TypeGuards.isValidNumber(NaN) // false
TypeGuards.isValidNumber(Infinity) // false
TypeGuards.isValidNumber('42') // false (stringa numerica)
Esempio: error handling difensivo
import { TypeGuards, RestError } from '@pzeta/postgrest'
try {
const user = await userRepo.read(1)
} catch (error) {
// 1. RestError già tipizzato dal repository
if (error instanceof RestError) {
handleRestError(error)
return
}
// 2. AxiosError raw (caso raro: errore prima di handleError)
if (TypeGuards.hasHttpResponse(error)) {
const { status, data } = error.response
if (TypeGuards.hasProperties(data, 'code', 'message') &&
TypeGuards.isNonEmptyString(data.code)) {
logger.error(`HTTP ${status} — ${data.code}: ${data.message}`)
} else {
logger.error(`HTTP ${status} — payload non standard`, data)
}
return
}
// 3. Errore di rete / generico
if (error instanceof Error) {
logger.error('Errore di rete:', error.message)
return
}
// 4. Tipo sconosciuto
logger.error('Errore non identificato:', error)
}
Esempio: validazione payload deserializzato
import { TypeGuards } from '@pzeta/postgrest'
function parseUserPayload(raw: unknown): User | null {
if (!TypeGuards.hasProperties(raw, 'idutente', 'nome', 'email')) {
return null
}
if (!TypeGuards.isValidNumber(raw.idutente)) return null
if (!TypeGuards.isNonEmptyString(raw.nome)) return null
if (!TypeGuards.isNonEmptyString(raw.email)) return null
// TypeScript ha narrowed correttamente
return {
idutente: raw.idutente,
nome: raw.nome,
email: raw.email,
}
}
data as User evita crash silenziosi quando l'API cambia shape. Il costo runtime è minimo (poche typeof/in checks).hasProperty e hasProperties controllano solo la presenza della chiave (prop in obj), non il tipo del valore associato (che resta unknown). Combina con isNonEmptyString / isValidNumber per validazione completa.Cross-reference
RepositoryUtils— usaTypeGuardsper costruireRestErrorRestError— errore tipizzato che ne è il risultato finalePostgRESTRepository— implementazione che propagaRestErrorai chiamanti
RepositoryUtils
Utility statiche per gestione errori PostgREST tipizzati (RestError), parsing path URL, generazione filter hash deterministici e costruzione cache key.
Auth
Autenticazione multi-strategia per @pzeta/postgrest. Supporta JWT Bearer, Cookie HTTP-only, API Key e NoAuth con interfaccia comune IAuthStrategy.