Loading...
Loading...
Use when modeling structured string patterns. Use when parsing DSLs like CSS selectors. Use when transforming string types. Use when validating string formats. Use when combining with mapped types.
npx skill4agent add marius-townhouse/effective-typescript-skills template-literal-typesinferinfer// RED FLAGS - Untyped strings that could be precise
type EventType = string; // Could be 'click' | 'hover' | etc.
function query(selector: string): Element; // Could parse CSS selectors
type CSSProperty = string; // Could validate property names// Match strings starting with a prefix
type PseudoString = `pseudo${string}`;
const science: PseudoString = 'pseudoscience'; // OK
const alias: PseudoString = 'pseudonym'; // OK
const physics: PseudoString = 'physics'; // Error!
// Match specific patterns
type DataAttribute = `data-${string}`;
type HTTPSUrl = `https://${string}`;
type VersionString = `v${number}.${number}.${number}`;// Allow data-* attributes while keeping type safety
interface Checkbox {
id: string;
checked: boolean;
[key: `data-${string}`]: unknown;
}
const check: Checkbox = {
id: 'subscribe',
checked: true,
'data-listIds': 'all-the-lists', // OK
value: 'yes', // Error: not data-* and not known property
};inferinfer// Extract event name from handler type
type EventName<T> = T extends `on${infer Name}` ? Name : never;
type ClickEvent = EventName<'onClick'>; // 'Click'
type HoverEvent = EventName<'onMouseEnter'>; // 'MouseEnter'
type BadEvent = EventName<'handleClick'>; // never
// Extract path parameters
type PathParams<T> = T extends `/users/${infer UserId}/posts/${infer PostId}`
? { userId: UserId; postId: PostId }
: never;
type Params = PathParams<'/users/123/posts/456'>;
// { userId: '123'; postId: '456' }// Convert snake_case to camelCase
type CamelCase<S extends string> =
S extends `${infer Head}_${infer Tail}`
? `${Head}${Capitalize<CamelCase<Tail>>}`
: S;
type T1 = CamelCase<'foo'>; // 'foo'
type T2 = CamelCase<'foo_bar'>; // 'fooBar'
type T3 = CamelCase<'foo_bar_baz'>; // 'fooBarBaz'
// Apply to object keys
type CamelCaseKeys<T> = {
[K in keyof T as CamelCase<K & string>]: T[K]
};
type SnakeCase = { user_name: string; email_address: string };
type Camel = CamelCaseKeys<SnakeCase>;
// { userName: string; emailAddress: string }// Enhance querySelector with precise types
type HTMLTag = keyof HTMLElementTagNameMap;
declare global {
interface ParentNode {
// Simple tag selector
querySelector<TagName extends HTMLTag>(
selector: TagName
): HTMLElementTagNameMap[TagName] | null;
// Tag#id selector
querySelector<TagName extends HTMLTag>(
selector: `${TagName}#${string}`
): HTMLElementTagNameMap[TagName] | null;
}
}
// Usage
const img = document.querySelector('img#hero');
// Type: HTMLImageElement | null
// Can access img?.src, img?.alt, etc.
const div = document.querySelector('div#container');
// Type: HTMLDivElement | null// Create event handler types from event names
type EventMap = {
click: MouseEvent;
keydown: KeyboardEvent;
submit: SubmitEvent;
};
type EventHandlers<Events extends Record<string, Event>> = {
[K in keyof Events as `on${Capitalize<K & string>}`]?:
(event: Events[K]) => void;
};
type Handlers = EventHandlers<EventMap>;
// {
// onClick?: (event: MouseEvent) => void;
// onKeydown?: (event: KeyboardEvent) => void;
// onSubmit?: (event: SubmitEvent) => void;
// }stringinfer| Anti-Pattern | Why It's Bad |
|---|---|
| Misses validation opportunity |
| Complex template types without testing | May be inaccurate |
| Parsing without escape hatches | Complex selectors need fallback |
| Overly precise types | Can break legitimate use cases |
'user-123''users-123'| Pattern | Syntax | Use Case |
|---|---|---|
| Prefix | | data attributes |
| Suffix | | event names |
| Middle | | file extensions |
| Extract | | parsing |
| Transform | | camelCase |
infer