A Comprehensive Guide to TypeScript: Indexable Types, Interfaces vs Types, Generics, Utility Types, and More
This article provides an in‑depth overview of TypeScript, covering its motivation over JavaScript, indexable types, the differences between interface and type, inheritance with extends, the keyof operator, generics, utility types such as Partial and Omit, type assertions, function overloads, and practical usage tips, all illustrated with clear code examples.
Introduction – JavaScript is a great language but has many design‑time pitfalls; TypeScript adds static typing to reshape developers' thinking and improve code quality.
Indexable Types – Demonstrates how to declare an interface with numeric and string index signatures, how the index type is inferred, and how to make them readonly.
interface StringArray {
[index: number]: string;
}
let myArray: StringArray = ["Bob", "Fred"];
let myStr: string = myArray[0];Shows that numeric indexes are converted to strings at runtime, and that a numeric index must return a subtype of the string index return type.
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!interface vs type – Explains that both keywords describe object shapes but differ in merging, re‑declaration, and ability to represent primitive, union, and tuple types.
// interface can be merged automatically
interface Point { x: number; y: number; }
interface Point { z: number; }
// type cannot be merged
type Point = { x: number; y: number; };
// type can express unions and intersections
type Name = string;
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
type PartialPoint = PartialPointX | PartialPointY;Extends and inheritance – Shows how interfaces and types can extend other types, and that extending cannot change the type of an existing property.
type num = { num: number; };
interface IStrNum extends num { str: string; }
// equivalent using intersection
type TStrNum = num & { str: string; };keyof operator – Extracts the literal union of an object's property names, turning runtime keys into a compile‑time type.
interface IQZQD { cnName: string; age: number; author: string; }
type Ant = keyof IQZQD; // "cnName" | "age" | "author"Generics – Introduces generic functions, interfaces, classes, constraints, and shows practical examples such as a logging function and a generic class.
function log
(value: T): T {
console.log(value);
return value;
}
log
(["a", "b", "c"]);
log("Nealyang");
interface Log
{ (value: T): T; }
let myLog: Log
= log;
myLog(1);
class Log
{
run(value: T) { console.log(value); return value; }
}
const log1 = new Log
();
log1.run(1);
const log2 = new Log();
log2.run({ a: 1 });Shows constraint example with a Length interface.
interface Length { length: number; }
function logAdvance
(value: T): T {
console.log(value, value.length);
return value;
}
logAdvance([1]);
logAdvance("123");
logAdvance({ length: 3 });Utility Types – Covers Partial, Required, Readonly, Record, Pick, Exclude, Extract, Omit with their definitions and usage examples.
type Partial
= { [P in keyof T]?: T[P] };
type Required
= { [P in keyof T]-?: T[P] };
type Readonly
= { readonly [P in keyof T]: T[P] };
type Record
= { [P in K]: T };
type Pick
= { [P in K]: T[P] };
type Exclude
= T extends U ? never : T;
type Extract
= T extends U ? T : never;
type Omit
= Pick
>;
// Example usages
type Person = { name: string; age: number; };
type PartialPerson = Partial
; // { name?: string; age?: number; }
type RequiredPerson = Required
; // { name: string; age: number; }
type ReadonlyPerson = Readonly
; // { readonly name: string; readonly age: number; }
type PersonRecord = Record<'a' | 'b' | 'c', Person>; // { a: Person; b: Person; c: Person; }
type PickName = Pick
; // { name: string; }
type Excluded = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // 'b' | 'd'
type Extracted = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // 'a' | 'c'
type Omitted = Omit
; // { age: number; }Type Assertions – Shows how to use the as syntax to tell the compiler a value has a specific type.
interface INealyang { enName: string; cnName: string; }
const nealyang = {} as INealyang;
nealyang.enName = "Nealyang";
nealyang.cnName = "一凨";Function Overloads – Demonstrates declaring multiple signatures for a function to enforce different parameter combinations.
interface User { name: string; age: number; }
declare function test(para: User): number;
declare function test(para: number, flag: boolean): number;
const user = { name: "Jack", age: 666 };
// const res = test(user, false); // error – overload does not matchPractical TS Usage – Provides links to articles about decorators, project architecture with Rax + TypeScript + hooks, and a list of reference materials.
References – Includes links to Chinese TypeScript documentation, advanced type cheat sheets, and various blog posts.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.