# TypeScript Advanced Patterns: Generics, Types as Tests

Source: https://www.techinterview.org/post/3233475106/typescript-advanced-patterns-generics-types/
Updated: 2026-05-05 · techinterview.org

TypeScript fluency is now baseline for senior frontend roles. Beyond the basics (interfaces, type aliases, basic generics), interviews probe whether you understand the type system as a small but capable functional language — capable of expressing complex constraints and catching bugs at compile time.

## Generics deeper

Generic constraints with `extends`:


```
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  // ...
}
```


The constraint `K extends keyof T` means K must be a key of T. Misuse is caught at the call site.

## Conditional types

The basic form:


```
type IsString<T> = T extends string ? true : false;
```


More useful: distribute over unions.


```
type ToArray<T> = T extends any ? T[] : never;
type R = ToArray<string | number>; // string[] | number[]
```


## Mapped types

Transform every property:


```
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type Partial<T> = { [K in keyof T]?: T[K] };
```


These are built-in but illustrate the pattern. Combine with conditional types for sophisticated transforms.

## Template literal types

String types with template-like composition:


```
type EventName<T extends string> = `on${Capitalize<T>}`;
type R = EventName<'click'>; // 'onClick'
```


Used in libraries for inferring types from string keys (Tailwind classes, route paths, etc.).

## Inferring with infer

Extract a type from another:


```
type ReturnType<T> = T extends (...args: any) => infer R ? R : never;
type R = ReturnType<() => string>; // string
```


Powerful for library types. Used in React for inferring component props, in Zod for inferring schemas.

## Discriminated unions

One of the most-used patterns:


```
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
```


Switching on the discriminator narrows the type:


```
if (result.ok) {
  console.log(result.value); // type narrowed to T
} else {
  console.log(result.error); // type narrowed to string
}
```


## Branded types

Distinguish between types that share a structure:


```
type UserId = string & { __brand: 'UserId' };
type CompanyId = string & { __brand: 'CompanyId' };

function getUser(id: UserId) { /* ... */ }
const cid = "abc" as CompanyId;
getUser(cid); // type error — cannot pass CompanyId where UserId is expected
```


Useful for IDs, monetary amounts, units.

## Const assertions

`as const` makes the type as narrow as possible:


```
const colors = ['red', 'green', 'blue'] as const;
type Color = typeof colors[number]; // 'red' | 'green' | 'blue'
```


Critical for deriving types from runtime values.

## Types as tests

For library authors, type-level tests catch regressions:


```
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false;

type _ = Expect<Equal<ReturnType<() => string>, string>>;
```


If the assertion fails, TypeScript errors at compile time.

## Common pitfalls

- `any` as escape hatch — defeats the purpose

- `as` casts to bypass type errors — usually a bug masking

- Excessive optionality (`?`) when properties are actually required

- Using `{}` as "any object" — actually means non-null

- Object index types like `[k: string]: any` — loses type safety

## Strict mode

Enable in tsconfig:


```
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}
```


Strict mode + the additional flags catches more bugs. Mandatory for serious code.

## The Zod pattern

Zod schemas double as runtime validators and types:


```
const Schema = z.object({ email: z.string().email(), age: z.number() });
type Data = z.infer<typeof Schema>;
```


One source of truth for runtime + compile-time. Used everywhere in 2026.

## Frequently Asked Questions

### Should I use TypeScript for small projects?

For projects above a single file, yes. The friction is minimal; the benefits compound.

### How do I handle third-party libraries without types?

Look for @types/ definitions on DefinitelyTyped. If none exist, write a small declaration file or contribute to the library.

### Are template literal types overkill?

For most app code: yes. For library code (especially type-safe APIs and DSLs): often essential.
