Patrones TypeScript estrictos para este portfolio (Vue 3 + Nuxt 4). Trigger: Al definir tipos, interfaces, composables tipados o props de componentes Vue.
// ✅ ALWAYS: una interfaz por entidad, sin objetos inline
interface Project {
_id: string
title: string
description?: string
imageUrl?: string
technologies?: string[]
githubUrl?: string
liveUrl?: string
}
// ❌ NEVER: objetos anidados inline
interface Project {
meta: { githubUrl: string; liveUrl: string } // NO
}
any// ✅ unknown para tipos verdaderamente desconocidos
function parse(input: unknown): Profile {
if (isProfile(input)) return input
throw new Error('Invalid input')
}
// ✅ Genéricos para flexibilidad
const useSanityQuery = async <T>(query: string) => { ... }
// ❌ NEVER
function fetch(data: any): any { }
// ✅ Siempre con interfaz explícita
interface Props {
profile?: Profile | null
projects?: Project[] | null
}
const props = defineProps<Props>()
// ❌ NEVER: runtime props sin tipos
defineProps(['profile', 'projects'])
// ✅ Objeto const → tipo derivado
const SECTIONS = {
HERO: 'hero',
ABOUT: 'about',
PROJECTS: 'projects',
CONTACT: 'contact',
} as const
type Section = (typeof SECTIONS)[keyof typeof SECTIONS]
// ❌ NEVER: union literal directo
type Section = 'hero' | 'about' | 'projects' | 'contact'
function isProfile(value: unknown): value is Profile {
return (
typeof value === 'object' &&
value !== null &&
'name' in value
)
}
// ✅ Usar import type para tipos puros
import type { Profile } from '~/types'