Type Utilities
Type utilities provide stronger type safety guarantees when working with flag codes in TypeScript.
Why Type Utilities?
Section titled “Why Type Utilities?”When working with flag codes from external sources (APIs, user input, databases), you often face a trade-off:
- Loose typing (
string): Runtime errors, no autocomplete - Strict typing (
FlagCode): Compile-time errors, but requires validation
Type utilities bridge this gap by providing:
- Runtime validation with
isFlagCode() - Type coercion with
coerceFlagCode() - Type-safe unions with
FlagCodetype
Import
Section titled “Import”import { coerceFlagCode, isFlagCode } from '@sankyu/react-circle-flags'import { type FlagCode } from '@sankyu/react-circle-flags'<script setup lang="ts">import { coerceFlagCode, isFlagCode } from '@sankyu/vue-circle-flags'import { type FlagCode } from '@sankyu/vue-circle-flags'</script>import { coerceFlagCode, isFlagCode } from '@sankyu/solid-circle-flags'import { type FlagCode } from '@sankyu/solid-circle-flags'API Reference
Section titled “API Reference”FlagCode type
Section titled “FlagCode type”A union type of all valid country/subdivision codes.
type FlagCode = 'ad' | 'ae' | 'af' | ... | 'zw' | 'gb-eng' | 'gb-nir' | ...Usage:
// ✅ Valid - TypeScript will autocomplete all 400+ codesconst code: FlagCode = 'us'
// ❌ Error - Type '"invalid"' is not assignable to type 'FlagCode'const invalid: FlagCode = 'invalid'isFlagCode(code: string): code is FlagCode
Section titled “isFlagCode(code: string): code is FlagCode”Type guard that checks if a string is a valid flag code.
isFlagCode('us') // trueisFlagCode('US') // false (expects normalized lowercase input)isFlagCode('invalid') // falsecoerceFlagCode(code: string, fallback?: FlagCode): FlagCode
Section titled “coerceFlagCode(code: string, fallback?: FlagCode): FlagCode”Safely converts a string to a valid flag code.
- If the value is a valid flag code (case-insensitive), returns the lowercase version
- Otherwise, returns the fallback (default:
'xx')
coerceFlagCode('US') // 'us'coerceFlagCode('Us') // 'us'coerceFlagCode('invalid') // 'xx' (default fallback)coerceFlagCode('invalid', 'un') // 'un' (custom fallback)coerceFlagCode('GB-ENG') // 'gb-eng'Usage Examples
Section titled “Usage Examples”Type narrowing with isFlagCode
Section titled “Type narrowing with isFlagCode”Use isFlagCode() in conditionals to narrow types:
import { isFlagCode } from '@sankyu/react-circle-flags'import { DynamicFlag } from '@sankyu/react-circle-flags'
export function CountryFlag({ code }: { code: string }) { // Validate and normalize first const normalized = code.trim().toLowerCase()
if (isFlagCode(normalized)) { // TypeScript knows `normalized` is FlagCode here return <DynamicFlag code={normalized} strict width={32} height={32} /> }
// Fallback for invalid codes return <span className="text-red-500">{code.toUpperCase()} (invalid)</span>}<script setup lang="ts">import { computed } from 'vue'import { isFlagCode } from '@sankyu/vue-circle-flags'import { DynamicFlag } from '@sankyu/vue-circle-flags'
const props = defineProps<{ code: string }>()
const normalized = computed(() => props.code.trim().toLowerCase())const isValid = computed(() => isFlagCode(normalized.value))</script>
<template> <DynamicFlag v-if="isValid" :code="normalized" strict :width="32" :height="32" /> <span v-else class="text-red-500"> {{ props.code.toUpperCase() }} (invalid) </span></template>Safe coercion with coerceFlagCode
Section titled “Safe coercion with coerceFlagCode”Use coerceFlagCode() to handle unknown strings safely:
import { coerceFlagCode } from '@sankyu/react-circle-flags'import { DynamicFlag } from '@sankyu/react-circle-flags'
export function CountryFlag({ codeFromApi }: { codeFromApi: string }) { // Coerce to a safe FlagCode (invalid codes become 'xx') const safeCode = coerceFlagCode(codeFromApi)
// Now we can use strict mode with full type safety return <DynamicFlag code={safeCode} strict width={32} height={32} />}<script setup lang="ts">import { computed } from 'vue'import { coerceFlagCode } from '@sankyu/vue-circle-flags'import { DynamicFlag } from '@sankyu/vue-circle-flags'
const props = defineProps<{ codeFromApi: string }>()
const safeCode = computed(() => coerceFlagCode(props.codeFromApi))</script>
<template> <DynamicFlag :code="safeCode" strict :width="32" :height="32" /></template>Custom fallback
Section titled “Custom fallback”Provide a custom fallback for invalid codes:
import { coerceFlagCode } from '@sankyu/react-circle-flags'import { DynamicFlag } from '@sankyu/react-circle-flags'import { type FlagCode } from '@sankyu/react-circle-flags'
export function CountryFlag({ code, fallbackCode = 'un',}: { code: string fallbackCode?: FlagCode}) { // Use a custom fallback instead of 'xx' const safeCode = coerceFlagCode(code, fallbackCode) return <DynamicFlag code={safeCode} strict width={32} height={32} />}Form validation
Section titled “Form validation”Validate form input with type safety:
import { useState } from 'react'import { isFlagCode, type FlagCode } from '@sankyu/react-circle-flags'
export function CountryForm() { const [code, setCode] = useState('') const [error, setError] = useState('')
const handleSubmit = () => { const normalized = code.trim().toLowerCase()
if (!isFlagCode(normalized)) { setError('Invalid country code') return }
// TypeScript knows `normalized` is FlagCode here const validCode: FlagCode = normalized console.log('Valid code:', validCode) setError('') }
return ( <form onSubmit={e => e.preventDefault()}> <input value={code} onChange={e => setCode(e.target.value)} placeholder="Enter country code" /> {error && <p className="text-red-500">{error}</p>} <button onClick={handleSubmit}>Submit</button> </form> )}<script setup lang="ts">import { ref } from 'vue'import { isFlagCode, type FlagCode } from '@sankyu/vue-circle-flags'
const code = ref('')const error = ref('')
const handleSubmit = () => { const normalized = code.value.trim().toLowerCase()
if (!isFlagCode(normalized)) { error.value = 'Invalid country code' return }
// TypeScript knows `normalized` is FlagCode here const validCode: FlagCode = normalized console.log('Valid code:', validCode) error.value = ''}</script>
<template> <form @submit.prevent="handleSubmit"> <input v-model="code" placeholder="Enter country code" /> <p v-if="error" class="text-red-500">{{ error }}</p> <button type="submit">Submit</button> </form></template>Strict Mode with DynamicFlag
Section titled “Strict Mode with DynamicFlag”Combine type utilities with strict prop for maximum type safety:
import { coerceFlagCode } from '@sankyu/react-circle-flags'import { DynamicFlag } from '@sankyu/react-circle-flags'
export function CountryFlag({ codeFromApi }: { codeFromApi: string }) { // Coerce unknown string to valid FlagCode const safeCode = coerceFlagCode(codeFromApi)
// strict mode ensures TypeScript validates the code at compile time return <DynamicFlag code={safeCode} strict width={32} height={32} />}<script setup lang="ts">import { computed } from 'vue'import { coerceFlagCode } from '@sankyu/vue-circle-flags'import { DynamicFlag } from '@sankyu/vue-circle-flags'
const props = defineProps<{ codeFromApi: string }>()const safeCode = computed(() => coerceFlagCode(props.codeFromApi))</script>
<template> <DynamicFlag :code="safeCode" strict :width="32" :height="32" /></template>Comparison
Section titled “Comparison”| Utility | Runtime Check | Return Type | Use Case |
|---|---|---|---|
isFlagCode() | Yes | code is FlagCode | Type narrowing in conditionals |
coerceFlagCode() | Yes | FlagCode | Safe conversion with fallback |
FlagCode type | No (zero-cost) | FlagCode | Compile-time type annotation |
See also
Section titled “See also” FlagUtils Toolkit Common utility functions for flag codes
Dynamic Flags Render flags from runtime ISO codes
API Reference Full type utilities API documentation