| name | typescript-type-system |
| user-invocable | false |
| description | Use when working with TypeScript's type system including strict mode, advanced types, generics, type guards, and compiler configuration. |
| allowed-tools | ["Bash","Read"] |
TypeScript Type System
Master TypeScript's type system features to write type-safe code. This
skill focuses exclusively on TypeScript language capabilities.
TypeScript Compiler
tsc --noEmit
tsc --noEmit -p tsconfig.json
tsc --version
tsc --noEmit --watch
Strict Mode Configuration
tsconfig.json strict mode options:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"useUnknownInCatchVariables": true
}
}
Essential Compiler Options
{
"compilerOptions": {
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
Advanced Type Patterns
Union and Intersection Types
type Status = "pending" | "active" | "completed";
type ID = string | number;
type Result = Success | Error;
type User = Person & Employee;
type Props = BaseProps & { extended: true };
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number }
| { kind: "rectangle"; width: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape. ** ;
:
shape. ** ;
:
shape. * shape.;
}
}
Generics
function identity<T>(value: T): T {
return value;
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
interface Repository<T> {
find(id: string): Promise<T | null>;
save(entity: T): Promise<T>;
delete(id: string): Promise<void>;
}
class DataStore<T extends { id: string }> {
private items = new Map<string, T>();
add(item: T): void {
this.items.set(item.id, item);
}
get(id: string): T | {
..(id);
}
}
<T = > = {
: T;
: ;
};
Conditional Types
type IsString<T> = T extends string ? true : false;
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type Flatten<T> = T extends Array<infer U> ? U : T;
type DeepFlatten<T> = T extends Array<infer U> ? DeepFlatten<U> : T;
type NonNullable<T> = T extends null | undefined ? never : T;
Mapped Types
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type PickByType<T, U> = {
[P in keyof T as T[P] extends U ? P : never]: T[P];
};
Template Literal Types
type EventName = "click" | "focus" | "blur";
type Handler = `on${Capitalize<EventName>}`;
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = `/api/${string}`;
type Route = `${HTTPMethod} ${Endpoint}`;
type ExtractRouteParams<T extends string> =
T extends `${string}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<Rest>
: T extends `${string}:${infer Param}`
? Param
: never;
type Params = ExtractRouteParams<"/users/:userId/posts/:postId">;
<T> = {
[K keyof T < & K>]: T[K];
};
Type Narrowing
Type Guards
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move() {
( animal) {
animal.();
} {
animal.();
}
}
(): value is {
value === ;
}
(): obj is { : ; : } {
(
obj === &&
obj !== &&
obj &&
obj &&
obj. === &&
obj. ===
);
}
(): asserts condition {
(!condition) {
(msg);
}
}
(): asserts value is {
( value !== ) {
();
}
}
Discriminated Unions
type NetworkState =
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; error: Error };
function handleNetwork(state: NetworkState) {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return state.data;
case "error":
return state.error.message;
}
}
type Response =
| { kind: "ok"; status: 200; data: string }
| { kind: "redirect"; status: 301 | 302; location: string }
| { kind: "error"; status: | ; : };
Truthiness Narrowing
function printAll(strs: string | string[] | null) {
if (strs && typeof strs === "object") {
for (const s of strs) {
console.log(s);
}
} else if (typeof strs === "string") {
console.log(strs);
}
}
Utility Types
Built-in Utility Types
type User = { name: string; age: number };
type PartialUser = Partial<User>;
type RequiredUser = Required<PartialUser>;
type ReadonlyUser = Readonly<User>;
type PageInfo = Record<"home" | "about" | "contact", { title: string }>;
type UserName = Pick<User, "name">;
type UserWithoutAge = Omit<User, "age">;
T = < | | , >;
= < | | , | >;
= < | | >;
() { { : , : }; }
P = < f>;
() {}
= < f2>;
{
() {}
}
= < C>;
= < C>;
A = <<>>;
B = <<<>>>;
Type Assertions and Casting
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength2: number = (someValue as string).length;
function liveDangerously(x?: number | null) {
console.log(x!.toFixed());
}
let x = "hello" as const;
let y = [10, 20] as const;
let z = { text: "hello" } as const;
const a = (expr as unknown) as T;
= { : ; : ; : } | ;
red = { : , : , : } ;
blue = ;
Type-Only Imports and Exports
import type { User, Product } from "./types";
import type * as Types from "./types";
import { type User, createUser } from "./user";
export type { User, Product };
export type * from "./types";
import { type User } from "./user";
Index Signatures and Mapped Types
interface StringMap {
[key: string]: string;
}
interface NumberArray {
[index: number]: number;
}
interface Dictionary {
[key: string]: string;
name: string;
}
interface Events {
[key: `on${string}`]: (event: Event) => void;
}
interface Data {
[key: string]: number;
}
const data: Data = {};
const value = data["key"];
type SafeData = Record<string, number>;
Advanced Patterns
Branded Types
type Brand<K, T> = K & { __brand: T };
type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;
function createUserId(id: string): UserId {
return id as UserId;
}
function getUserById(id: UserId) {
}
const userId = createUserId("123");
const orderId = "456" as OrderId;
getUserById(userId);
Builder Pattern with Fluent API
class QueryBuilder<T> {
private filters: Array<(item: T) => boolean> = [];
where(predicate: (item: T) => boolean): this {
this.filters.push(predicate);
return this;
}
execute(items: T[]): T[] {
return items.filter(item =>
this.filters.every(filter => filter(item))
);
}
}
const users = new QueryBuilder<{ name: string; age: number }>()
.where(u => u.age > 18)
.where(u => u.name.startsWith("A"))
.execute(allUsers);
Variadic Tuple Types
type Tuple1 = [string, number];
type Tuple2 = [boolean, ...Tuple1];
function concat<T extends unknown[], U extends unknown[]>(
arr1: [...T],
arr2: [...U]
): [...T, ...U] {
return [...arr1, ...arr2];
}
type Range = [start: number, end: number];
type Point = [x: number, y: number, z?: number];
Common Type Patterns
Recursive Types
type JSONValue =
| string
| number
| boolean
| null
| JSONValue[]
| { [key: string]: JSONValue };
type NestedArray<T> = T | NestedArray<T>[];
type DeepPartial<T> = T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
Function Overloads
function createElement(tag: "div"): HTMLDivElement;
function createElement(tag: "span"): HTMLSpanElement;
function createElement(tag: "canvas"): HTMLCanvasElement;
function createElement(tag: string): HTMLElement {
return document.createElement(tag);
}
class EventEmitter {
on(event: "data", handler: (data: string) => void): void;
on(event: "error", handler: (error: Error) => void): void;
on(event: string, handler: () => ): {
}
}
Type Predicates with Generics
function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
const values = [1, null, 2, undefined, 3];
const numbers = values.filter(isDefined);
function isArrayOf<T>(
arr: unknown,
check: (item: unknown) => item is T
): arr is T[] {
return Array.isArray(arr) && arr.every(check);
}
tsconfig.json Best Practices
Project References
{
"compilerOptions": {
"composite": true,
"declarationMap": true,
"incremental": true,
"tsBuildInfoFile": "./buildinfo"
},
"references": [
{ "path": "../shared" },
{ "path": "../utils" }
]
}
Path Mapping
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@app/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"],
"@types/*": ["src/types/*"]
}
}
}
Multiple Configurations
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true
}
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["**/*.test.ts"]
}
Type System Limitations
Things TypeScript Cannot Do
function process<T>(value: T) {
}
type User = { name: string };
type USD = number;
type EUR = number;
const usd: USD = 100;
const eur: EUR = usd;
type Point = { x: number; y: number };
const p: Point = { x: 1, y: 2, z: 3 };
const obj = { x: 1, y: 2, z: 3 };
const p2: = obj;
Resources