Typed Utils
Utility types for extracting option types and values from typed components.
Introduction
typed-utils provides utility types that power the type inference in all Typedora UI components. These types are automatically installed as a dependency when you add any typed component.
Key features:
- Extract option types from flat or grouped options arrays
- Extract value types based on custom value keys
- Full support for
as constarrays with literal types
Installation
npx shadcn@latest add https://typedora-ui.netlify.app/r/typed-utils.jsonpnpm dlx shadcn@latest add https://typedora-ui.netlify.app/r/typed-utils.jsonnpx shadcn@latest add https://typedora-ui.netlify.app/r/typed-utils.jsonbunx --bun shadcn@latest add https://typedora-ui.netlify.app/r/typed-utils.jsonNote
This package is automatically installed when you add any typed component like TypedSelect, TypedCombobox, or TypedRadioGroup.
Usage
ExtractOption
ExtractOption extracts the individual option type from an options array. It handles both flat options and grouped options.
import type { } from "@/lib/typed-utils";
// Flat options
const = [
{ : "apple", : "Apple" },
{ : "banana", : "Banana" },
] as ;
type Fruit = <typeof >;
// Grouped options
const = [
{
: "Tropical",
: [
{ : "mango", : "Mango" },
{ : "pineapple", : "Pineapple" },
],
},
] as ;
type GroupedFruit = <typeof >;ExtractOptionValue
ExtractOptionValue extracts the value type from options based on a specified key. This is useful when you need to type a variable that holds the selected value.
import type { } from "@/lib/typed-utils";
// With default "value" key
const = [
{ : "apple", : "Apple" },
{ : "banana", : "Banana" },
{ : "orange", : "Orange" },
] as ;
type FruitValue = <typeof , "value">;
// With custom "id" key
const = [
{ : 1, : "Alice" },
{ : 2, : "Bob" },
{ : 3, : "Charlie" },
] as ;
type UserId = <typeof , "id">;Real-world Example
Here's how you might use these utility types in a real application:
import { } from "react";
import type { } from "@/lib/typed-utils";
import { } from "@/components/typed-select";
const = [
{ : "pending", : "Pending", : "yellow" },
{ : "approved", : "Approved", : "green" },
{ : "rejected", : "Rejected", : "red" },
] as ;
// Type-safe state
type = <typeof , "value">;
function () {
const [, ] = < | undefined>();
// status is typed as "pending" | "approved" | "rejected" | undefined
return (
<
={}
={}
={}
="Filter by status"
/>
);
}Using with Grouped Options
Both utility types work seamlessly with grouped options:
import type { , } from "@/lib/typed-utils";
const = [
{
: "Asia",
: [
{ : "jp", : "Japan" },
{ : "kr", : "South Korea" },
{ : "vn", : "Vietnam" },
],
},
{
: "Europe",
: [
{ : "de", : "Germany" },
{ : "fr", : "France" },
{ : "uk", : "United Kingdom" },
],
},
] as ;
// Extracts the individual option (not the group)
type Country = <typeof >;
// Extracts just the value
type CountryCode = <typeof , "value">;API Reference
ExtractOption<TOptions>
Extracts the inner option type from an options array.
type ExtractOption<TOptions> = TOptions extends readonly (infer T)[]
? T extends { options: readonly (infer O)[] }
? O
: T
: never;| Parameter | Description |
|---|---|
TOptions | The options array type (should be readonly with as const) |
Returns: Union type of all option objects in the array.
Behavior:
- For flat options: Returns the option type directly
- For grouped options: Extracts and returns the inner option type from
optionsproperty
ExtractOptionValue<TOptions, TValueKey>
Extracts the value type from options based on the specified key.
type ExtractOptionValue<
TOptions,
TValueKey extends string,
> = ExtractOption<TOptions> extends infer O
? O extends Record<string, unknown>
? TValueKey extends keyof O
? O[TValueKey] & {}
: never
: never
: never;| Parameter | Description |
|---|---|
TOptions | The options array type (should be readonly with as const) |
TValueKey | The key to extract values from (e.g., "value", "id") |
Returns: Union type of all values for the specified key.
Tips
Always use as const
For proper type inference, always use as const when defining your options:
// Good - literal types preserved
const options = [
{ value: "a", label: "A" },
{ value: "b", label: "B" },
] as const;
// Bad - types widened to string
const options = [
{ value: "a", label: "A" },
{ value: "b", label: "B" },
];Define options outside components
Define your options array outside the component to prevent recreation on each render and ensure stable type inference:
// Good - defined outside
const options = [...] as const;
function MyComponent() {
return <TypedSelect options={options} />;
}
// Avoid - recreated on each render
function MyComponent() {
const options = [...] as const; // recreated
return <TypedSelect options={options} />;
}