Master expert-level TypeScript: mapped types, conditional types, and declaration files for library-grade code.
Deep dive into mapped types, conditional types, and type declaration files.
Partial, Required, and Readonly work internally.// Basic syntax: [K in keyof T]
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
interface User {
name: string;
age: number;
}
type ReadonlyUser = MyReadonly<User>;
// Result: { readonly name: string; readonly age: number; }type MyPartial<T> = {
[K in keyof T]?: T[K];
};
type PartialUser = MyPartial<User>;
// Result: { name?: string; age?: number; }type MyRequired<T> = {
[K in keyof T]-?: T[K]; // -? removes optional
};
interface Config {
debug?: boolean;
verbose?: boolean;
}
type RequiredConfig = MyRequired<Config>;
// Result: { debug: boolean; verbose: boolean; }type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface Person {
name: string;
age: number;
email: string;
}
type NameAndAge = MyPick<Person, "name" | "age">;
// Result: { name: string; age: number; }type MyRecord<K extends keyof any, V> = {
[P in K]: V;
};
type StringMap = MyRecord<"a" | "b" | "c", number>;
// Result: { a: number; b: number; c: number; }type Getters<T> = {
[K in keyof T as \`get\${Capitalize<string & K>}\`]: () => T[K];
};
type UserGetters = Getters<User>;
// Result: { getName: () => string; getAge: () => number; }MyReadonly works: properties are readonly
MyPartial works: properties are optional
MyPick works: selected properties only
MyRecord works: key-value mapping created
Getters created: getName, getAge
type T<X> = { [K in keyof X]: X[K] }readonly [K in keyof T][K in keyof T]?[K in keyof T]-?K extends keyof TReview feedback below
// T extends U ? X : Y
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false// Extract: keep types that match
type MyExtract<T, U> = T extends U ? T : never;
type Numbers = MyExtract<string | number | boolean, number>;
// Result: number
// Exclude: remove types that match
type MyExclude<T, U> = T extends U ? never : T;
type NotNumbers = MyExclude<string | number | boolean, number>;
// Result: string | booleantype MyNonNullable<T> = T extends null | undefined ? never : T;
type MaybeString = string | null | undefined;
type DefinitelyString = MyNonNullable<MaybeString>;
// Result: string// Extract return type of a function
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Fn = (x: number) => string;
type FnReturn = MyReturnType<Fn>; // string
// Extract element type from array
type ArrayElement<T> = T extends (infer E)[] ? E : never;
type NumArray = number[];
type Element = ArrayElement<NumArray>; // numbertype MyParameters<T> = T extends (...args: infer P) => any ? P : never;
type Fn2 = (a: string, b: number) => void;
type Params = MyParameters<Fn2>; // [string, number]// Unions are distributed automatically
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>;
// Result: string[] | number[] (not (string | number)[])IsString<string> = true
MyExtract<string|number, number> = number
MyReturnType works: extracted return type
MyParameters works: extracted params
Conditional types demonstration complete!
T extends U ? X : Ynever to filter out typesinfer R captures a type in the pattern(...args: any[]) => infer R(...args: infer P) => anyReview feedback below
// my-library.d.ts
declare module "my-library" {
export function greet(name: string): string;
export function calculate(a: number, b: number): number;
export const VERSION: string;
}// globals.d.ts
declare global {
interface Window {
myApp: {
version: string;
init(): void;
};
}
var DEBUG: boolean;
function legacyFunction(x: string): void;
}declare class MyWidget {
constructor(element: HTMLElement);
render(): void;
destroy(): void;
readonly id: string;
}declare interface Config {
apiUrl: string;
timeout?: number;
retries?: number;
}
declare type EventHandler = (event: Event) => void;
declare interface EventEmitter {
on(event: string, handler: EventHandler): void;
off(event: string, handler: EventHandler): void;
emit(event: string, data?: any): void;
}declare namespace MyLib {
interface Options {
debug: boolean;
logLevel: "info" | "warn" | "error";
}
function init(options: Options): void;
function shutdown(): void;
namespace Utils {
function format(str: string): string;
function parse(data: string): object;
}
}// For JSON imports
declare module "*.json" {
const value: any;
export default value;
}
// For CSS modules
declare module "*.css" {
const classes: { [key: string]: string };
export default classes;
}
// For image imports
declare module "*.png" {
const src: string;
export default src;
}Module declaration created
Global types declared
Class declaration valid
Namespace declaration complete
Ambient modules configured
declare module "name" { export ... }declare global { interface Window { } }declare class Name { method(): void; }declare namespace Name { function fn(): void; }declare module "*.ext" { }Review feedback below