generics-mastery — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited generics-mastery (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Build powerful, reusable type abstractions with generics. Generics let you write code that works across types while preserving full type safety.
Constrain type parameters to ensure they have required properties.
// Basic constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name"); // string
// getProperty(user, "email"); // Compile error
// Constraint with interface
interface HasId {
id: string;
}
function findById<T extends HasId>(items: readonly T[], id: string): T | undefined {
return items.find((item) => item.id === id);
}
// Multiple constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}Types that choose a branch based on a condition, like a type-level ternary.
// Basic conditional
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
// Distributive conditional types (distributes over unions)
type NonNullable<T> = T extends null | undefined ? never : T;
type C = NonNullable<string | null | undefined>; // string
// Extract and Exclude
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type Numbers = Extract<string | number | boolean, number>; // number
type WithoutBool = Exclude<string | number | boolean, boolean>; // string | number
// Conditional return types
function process<T extends string | number>(
value: T
): T extends string ? string[] : number {
if (typeof value === "string") {
return value.split("") as T extends string ? string[] : number;
}
return (value * 2) as T extends string ? string[] : number;
}Transform every property of an existing type.
// Make all properties optional
type Partial<T> = { [K in keyof T]?: T[K] };
// Make all properties required
type Required<T> = { [K in keyof T]-?: T[K] };
// Make all properties readonly
type Readonly<T> = { readonly [K in keyof T]: T[K] };
// Remap keys with `as`
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person { name: string; age: number }
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }
// Filter properties by value type
type PickByType<T, V> = {
[K in keyof T as T[K] extends V ? K : never]: T[K];
};
type StringProps = PickByType<Person, string>;
// { name: string }Extract types from inside other types within conditional type clauses.
// Extract return type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type R = ReturnType<() => string>; // string
// Extract promise value
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type V = Awaited<Promise<Promise<number>>>; // number
// Extract array element
type ElementOf<T> = T extends readonly (infer E)[] ? E : never;
type E = ElementOf<string[]>; // string
// Extract function parameters
type FirstParam<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;
type P = FirstParam<(name: string, age: number) => void>; // string
// Infer from template literals
type ParseRoute<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? Param | ParseRoute<Rest>
: T extends `${infer _Start}:${infer Param}`
? Param
: never;
type Params = ParseRoute<"/users/:userId/posts/:postId">;
// "userId" | "postId"Combine built-in and custom utility types for real-world scenarios.
// Updatable entity: id is required and readonly, rest is partial
type Updatable<T extends { id: string }> = Readonly<Pick<T, "id">> &
Partial<Omit<T, "id">>;
interface User {
id: string;
name: string;
email: string;
role: "admin" | "user";
}
type UserUpdate = Updatable<User>;
// { readonly id: string; name?: string; email?: string; role?: "admin" | "user" }
// Deep partial
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
// StrictOmit that validates the key exists
type StrictOmit<T, K extends keyof T> = Omit<T, K>;
// Record with specific keys
type ApiEndpoints = Record<"getUser" | "listUsers" | "createUser", string>;Types that reference themselves for tree structures and deep transformations.
// JSON type
type Json =
| string
| number
| boolean
| null
| Json[]
| { [key: string]: Json };
// Tree structure
interface TreeNode<T> {
value: T;
children: ReadonlyArray<TreeNode<T>>;
}
// Deep readonly
type DeepReadonly<T> = T extends (infer E)[]
? ReadonlyArray<DeepReadonly<E>>
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
// Path type for nested access
type Path<T, K extends keyof T = keyof T> = K extends string
? T[K] extends object
? K | `${K}.${Path<T[K]>}`
: K
: never;
interface Config {
db: { host: string; port: number };
cache: { ttl: number };
}
type ConfigPath = Path<Config>; // "db" | "cache" | "db.host" | "db.port" | "cache.ttl"add cognitive load; use them only when you need reuse across multiple types.
// BAD: unnecessary generic
function greet<T extends string>(name: T): string { return `Hi ${name}`; }
// GOOD: concrete type
function greet(name: string): string { return `Hi ${name}`; }unknown or a specific interface. extends anyprovides no safety.
nesting, consider breaking it into named helper types for readability.
Wrap in [T] to prevent distribution when you need to treat the union as a whole:
type IsUnion<T> = [T] extends [infer U] ? ([U] extends [T] ? false : true) : never;| Concept | Syntax | Purpose |
|---|---|---|
| Constraint | T extends U | Limit what T can be |
| Conditional | T extends U ? A : B | Branch on type |
| Mapped | { [K in keyof T]: ... } | Transform all props |
| Key remapping | as in mapped types | Rename/filter keys |
| infer | T extends F<infer U> | Extract inner type |
| Recursive | Self-referencing type | Trees, deep transforms |
| Distributive | Default on naked T | Applies to each union member |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.