typescript-best-practices

TypeScript Best Practices

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "typescript-best-practices" with this command: npx skills add zatkniz/sporty-group/zatkniz-sporty-group-typescript-best-practices

TypeScript Best Practices

Enforce project-wide TypeScript standards and conventions.

When to Use

DO USE when:

  • Writing any new TypeScript code

  • Creating or modifying Vue components

  • Defining new types or interfaces

  • Creating composables or utilities

  • Reviewing code for TypeScript compliance

  • Refactoring JavaScript to TypeScript

  • Questions about type definitions

  • Type organization and structure

DO NOT USE when:

  • Dealing with plain JavaScript (convert to TypeScript first)

  • Configuration files that don't support TypeScript

  • Third-party type definitions (use @types packages)

Critical Standards

⚠️ NON-NEGOTIABLE RULES

Type Location: ALL types MUST be in app/types/ directory

  • ✅ import type { User } from '~/types/user'

  • ❌ Defining types inside components/composables

Vue Components: ALWAYS use lang="ts"

  • ✅ <script setup lang="ts">

  • ❌ <script setup> without lang

Function Style: ONLY arrow functions

  • ✅ const myFunc = (): string => { ... }

  • ❌ function myFunc() { ... }

Return Types: ALWAYS specify return types

  • ✅ const getData = (): Promise<User[]> => { ... }

  • ❌ const getData = async () => { ... }

Explicit Types: NO implicit any

  • ✅ const items: Product[] = []

  • ❌ const items = []

Type Exports: ALWAYS export from app/types/

  • ✅ All types exported and imported

  • ❌ Local type definitions

Type Organization Structure

Directory Layout

app/ types/ user.ts # User-related types product.ts # Product types api.ts # API response types forms.ts # Form data types state.ts # State management types common.ts # Shared/utility types errors.ts # Error types index.ts # Optional re-exports

File Naming

  • Use singular for entity types: user.ts , product.ts

  • Use descriptive names: api.ts , forms.ts , state.ts

  • Group related types in same file

  • Export all types from each file

Code Patterns

Component Pattern

// ✅ CORRECT <script setup lang="ts"> import type { User, Product } from '~/types'

interface Props { user: User items: Product[] }

const props = defineProps<Props>()

const formatName = (user: User): string => { return ${user.firstName} ${user.lastName} } </script>

Composable Pattern

// ✅ CORRECT // app/composables/useData.ts import type { User, ApiResponse } from '~/types'

export const useData = () => { const data = ref<User | null>(null)

const fetchData = async (): Promise<User> => { const { data: response } = await useFetch<ApiResponse<User>>('/api/user') if (!response.value) throw new Error('No data') return response.value.data }

return { data, fetchData } }

Store Pattern

// ✅ CORRECT // app/stores/user.ts import type { User, LoginCredentials } from '~/types'

export const useUserStore = defineStore('user', () => { const user = ref<User | null>(null)

const login = async (creds: LoginCredentials): Promise<void> => { // Implementation }

return { user: readonly(user), login } })

Utility Pattern

// ✅ CORRECT // app/utils/formatters.ts import type { User, Product } from '~/types'

export const formatUser = (user: User): string => { return ${user.firstName} ${user.lastName} }

export const calculateTotal = (products: Product[]): number => { return products.reduce((sum: number, p: Product): number => sum + p.price, 0 ) }

Type Definition Patterns

Basic Entity Types

// app/types/user.ts export interface User { id: string email: string firstName: string lastName: string role: UserRole createdAt: Date }

export type UserRole = 'admin' | 'user' | 'guest'

API Response Types

// app/types/api.ts export interface ApiResponse<T> { data: T message: string success: boolean }

export interface PaginatedResponse<T> { items: T[] total: number page: number }

Form Types

// app/types/forms.ts export interface LoginForm { email: string password: string }

export interface FormField<T> { value: T error: string | null touched: boolean }

State Types

// app/types/state.ts export interface LoadingState { isLoading: boolean error: Error | null }

export interface DataState<T> extends LoadingState { data: T | null }

Common Violations & Fixes

❌ Inline Type Definition

<!-- WRONG --> <script setup lang="ts"> interface User { // ❌ Type defined inline id: string name: string } </script>

Fix: Move to app/types/user.ts

❌ Missing Return Type

// WRONG const getData = async () => { // ❌ No return type return data }

Fix: Add explicit return type

// CORRECT const getData = async (): Promise<Data> => { return data }

❌ Function Keyword

// WRONG function handleClick() { // ❌ function keyword // ... }

Fix: Use arrow function

// CORRECT const handleClick = (): void => { // ... }

❌ Missing lang="ts"

<!-- WRONG --> <script setup> <!-- ❌ No lang="ts" --> const data = ref() </script>

Fix: Add lang="ts"

<!-- CORRECT --> <script setup lang="ts"> const data = ref<string>('') </script>

❌ Implicit Any

// WRONG const items = [] // ❌ Implicit any[] const user = ref() // ❌ Implicit any

Fix: Add explicit types

// CORRECT const items: string[] = [] const user = ref<User | null>(null)

Refactoring Checklist

When reviewing or refactoring TypeScript code:

  • All types defined in app/types/ directory

  • All Vue components use lang="ts"

  • All functions are arrow functions

  • All functions have explicit return types

  • No function keyword usage

  • No inline type definitions

  • No any types (use unknown if needed)

  • All variables have explicit types

  • Imports use import type for types

  • Generic types properly constrained

tsconfig Enforcement

Ensure these are enabled in tsconfig.json :

{ "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true } }

Quick Reference

✅ DO

  • Export all types from app/types/

  • Use lang="ts" in all Vue components

  • Use arrow functions exclusively

  • Specify return types on all functions

  • Use explicit types for all variables

  • Import types with import type

  • Use unknown instead of any

  • Document complex types with JSDoc

❌ DON'T

  • Define types inside components

  • Define types inside composables

  • Use function keyword

  • Omit return types

  • Use implicit any

  • Use any type

  • Define types in non-types files

  • Forget lang="ts" in components

Integration with Project

This TypeScript standard works with:

  • Components: lang="ts"
  • external types
  • Composables: Arrow functions + return types

  • Stores: Pinia with typed state/actions

  • Utils: Pure functions with explicit types

  • API: Typed requests/responses

Additional Resources

  • TypeScript Handbook

  • Vue 3 TypeScript Guide

  • Nuxt TypeScript

  • Pinia TypeScript

Example Workflow

User: "Create a user profile component"

  • Define types in app/types/user.ts

  • Create component with lang="ts"

  • Import types: import type { User } from '~/types'

  • Use arrow functions with return types

  • Verify all TypeScript standards followed

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

nuxt-ui-theming

No summary provided by upstream source.

Repository SourceNeeds Review
General

vueuse-composables

No summary provided by upstream source.

Repository SourceNeeds Review
General

nuxt-documentation-lookup

No summary provided by upstream source.

Repository SourceNeeds Review
General

nuxt-ui-component-finder

No summary provided by upstream source.

Repository SourceNeeds Review