TypeScript Support

NH-UI is built with TypeScript from the ground up, providing complete type safety and excellent developer experience.

100% Type Safe

IntelliSense

Full autocomplete for all component props, including descriptions and default values.

Type Checking

Catch errors at compile time, not runtime. Invalid props are highlighted immediately.

Refactoring

Rename props, update types, and refactor with confidence using IDE tools.

Component Types

Importing Types
import { 
  NHButton, 
  NHButtonProps,
  NHCard,
  NHCardProps 
} from '@noiseheroes/ui';

// Using component prop types
const MyButton: React.FC<NHButtonProps> = (props) => {
  return <NHButton {...props} />;
};

// Extending component props
interface CustomButtonProps extends NHButtonProps {
  analytics?: {
    event: string;
    category: string;
  };
}

const TrackedButton: React.FC<CustomButtonProps> = ({ 
  analytics, 
  onClick,
  ...props 
}) => {
  const handleClick = (e: React.MouseEvent) => {
    if (analytics) {
      trackEvent(analytics.event, analytics.category);
    }
    onClick?.(e);
  };

  return <NHButton {...props} onClick={handleClick} />;
};

Working with Props

Typed Props with IntelliSense
// All props are fully typed with JSDoc comments
<NHButton
  color="primary"      // "primary" | "secondary" | "success" | "warning" | "danger"
  size="lg"            // "sm" | "md" | "lg"
  variant="solid"      // "solid" | "bordered" | "light" | "flat" | "faded" | "shadow"
  isLoading={false}    // boolean
  isDisabled={false}   // boolean
  startContent={<Icon />}  // React.ReactNode
  endContent={<Icon />}    // React.ReactNode
  onPress={(e) => {    // (e: PressEvent) => void
    console.log('Pressed!');
  }}
>
  Click me
</NHButton>

// TypeScript will catch these errors:
<NHButton
  color="invalid"      // ❌ Type '"invalid"' is not assignable to type Color
  size={123}           // ❌ Type 'number' is not assignable to type Size
  isLoading="false"    // ❌ Type 'string' is not assignable to type boolean
/>

Event Handler Types

Strongly Typed Events
import { NHInput, NHButton, NHSelect } from '@noiseheroes/ui';

// Input change event
<NHInput
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value; // string
    console.log('Input value:', value);
  }}
/>

// Button press event (HeroUI uses onPress instead of onClick)
<NHButton
  onPress={(e) => {
    // e is automatically typed as PressEvent
    console.log('Button pressed');
  }}
/>

// Select change event
<NHSelect
  onSelectionChange={(key: React.Key) => {
    // key is string | number
    console.log('Selected:', key);
  }}
>
  <NHSelectItem key="option1">Option 1</NHSelectItem>
  <NHSelectItem key="option2">Option 2</NHSelectItem>
</NHSelect>

// Form submission with type safety
interface FormData {
  email: string;
  password: string;
}

const handleSubmit = (data: FormData) => {
  // data is fully typed
  console.log(data.email, data.password);
};

Generic Components

Type-Safe Data Components
// Table with generic data types
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

<NHTable<User>
  data={users}
  columns={[
    {
      key: 'name',
      label: 'Name',
      render: (user) => user.name // user is typed as User
    },
    {
      key: 'email',
      label: 'Email',
      render: (user) => user.email
    },
    {
      key: 'role',
      label: 'Role',
      render: (user) => (
        <NHChip color={user.role === 'admin' ? 'primary' : 'default'}>
          {user.role}
        </NHChip>
      )
    }
  ]}
/>

// Select with typed options
interface Option {
  value: string;
  label: string;
  icon?: React.ReactNode;
}

const options: Option[] = [
  { value: 'react', label: 'React', icon: <ReactIcon /> },
  { value: 'vue', label: 'Vue', icon: <VueIcon /> },
  { value: 'angular', label: 'Angular', icon: <AngularIcon /> }
];

<NHSelect<Option>
  items={options}
  onSelectionChange={(selected) => {
    // selected is typed as Option
    console.log(selected.value, selected.label);
  }}
/>

Utility Types

NH-UI Type Utilities
import { 
  Color, 
  Size, 
  Variant,
  ResponsiveValue 
} from '@noiseheroes/ui';

// Using theme types
const primaryColor: Color = 'primary';
const buttonSize: Size = 'md';
const cardVariant: Variant = 'bordered';

// Responsive values
const responsivePadding: ResponsiveValue<number> = {
  base: 4,
  sm: 6,
  md: 8,
  lg: 10,
  xl: 12
};

// Component-specific types
import type { 
  NHButtonProps,
  NHCardProps,
  NHInputProps 
} from '@noiseheroes/ui';

// Creating custom component with NH-UI types
interface CustomCardProps extends NHCardProps {
  featured?: boolean;
  category?: 'blog' | 'product' | 'news';
}

const CustomCard: React.FC<CustomCardProps> = ({ 
  featured, 
  category,
  ...props 
}) => {
  return (
    <NHCard
      {...props}
      className={cn(
        props.className,
        featured && 'border-2 border-orange-500',
        category && `category-${category}`
      )}
    />
  );
};
TypeScript Best Practices

1. Use Type Imports

import type { NHButtonProps } from '@noiseheroes/ui';

Reduces bundle size by ensuring types are removed at build time.

2. Extend Component Props

interface MyProps extends NHCardProps { custom: string; }

Inherit all the original props while adding your own.

3. Use Discriminated Unions

type Status = { type: 'loading' } | { type: 'error'; message: string } | { type: 'success'; data: T };

TypeScript can narrow types based on discriminator fields.

4. Avoid Type Assertions

// ❌ Avoid: value as string // ✅ Prefer: proper typing or type guards

Let TypeScript infer types naturally for better safety.

Recommended tsconfig.json

TypeScript Configuration
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"],
      "@noiseheroes/ui": ["./node_modules/@noiseheroes/ui"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
HeroUI • Build: 2025-08-04T19:49:47.144Z