Unveiling the Hidden Treasures: Exploring Lesser-Known TypeScript Features

Jonas Pfalzgraf - Aug 8 '23 - - Dev Community

Greetings, fellow developers! While we traverse the familiar landscapes of TypeScript, there exists an uncharted territory brimming with lesser-known gems that can infuse your code with power and elegance. In this journey, we'll delve into the depths of TypeScript's enigmatic toolkit, uncovering features that might have eluded your radar but hold the potential to transform your coding experience. So, fasten your seatbelts as we embark on an exhilarating expedition to discover these unsung heroes of TypeScript!

1. Mapped Types: Crafting Dynamic Transformations

Picture a toolkit that empowers you to craft dynamic transformations for your types. Welcome to the realm of Mapped Types! These versatile constructs allow you to wield the magic of type manipulation, breathing new life into your code.

type MagicMap<T> = { [K in keyof T]: T[K] | null };

const originalObj = { name: "Merlin", age: 1000 };
const nullableObj: MagicMap<typeof originalObj> = { name: "Gandalf", age: null };
Enter fullscreen mode Exit fullscreen mode

Let's unravel the practical enchantment of mapped types:

type PartialAndNullable<T> = { [K in keyof T]?: T[K] | null };

interface User {
  id: number;
  name: string;
  email: string;
}

const partialUser: PartialAndNullable<User> = { id: 1, name: null };
Enter fullscreen mode Exit fullscreen mode

2. Conditional Types: Pioneering Type Predictions

Imagine gazing into a crystal ball that predicts and adapts types based on conditions. Say hello to Conditional Types! These mystical constructs enable you to weave intricate type logic, providing a dynamic edge to your code.

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

type CheckString = IsString<"Wizard">; // true
Enter fullscreen mode Exit fullscreen mode

Transcend into the realm of practical application:

type Pluck<T, K extends keyof T> = {
  [P in K]: T[P];
};

interface Spell {
  name: string;
  incantation: string;
  effect: string;
}

const spell: Pluck<Spell, "name" | "effect"> = {
  name: "Levitation",
  effect: "Objects float in the air",
};
Enter fullscreen mode Exit fullscreen mode

3. Tuple Type: Symphony of Ordered Abstractions

Envision a symphony where data harmoniously follows an ordered arrangement. This is the magic of Tuple Types! These structured envoys bring a touch of elegance to your arrays, preserving both sequence and data types.

type SpellComponent = [string, number];

const fireball: SpellComponent = ["Fire", 3];
Enter fullscreen mode Exit fullscreen mode

Harmonize your data with the power of tuples:

type Coordinate = [number, number];

function calculateDistance(pointA: Coordinate, pointB: Coordinate): number {
  const [x1, y1] = pointA;
  const [x2, y2] = pointB;
  return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
Enter fullscreen mode Exit fullscreen mode

4. Template Literal Types: Strings Amplified into Types

Imagine a realm where strings metamorphose into versatile types. Enter Template Literal Types, the enigmatic alchemy that binds strings and types in an intricate dance.

type Message<T> = `Hello, ${T}!`;

const greeting: Message<"Sorcerer"> = "Hello, mighty sorcerer!";
Enter fullscreen mode Exit fullscreen mode

Unveil the practical magic within template literals:

type JoinStrings<T extends string, U extends string> = `${T} ${U}`;

type Combined = JoinStrings<"Enchanted", "Forest">; // "Enchanted Forest"
Enter fullscreen mode Exit fullscreen mode

5. Infer Keyword: Unveiling the Cryptic Prophecies of Types

Enter the oracle's chamber, where types are unveiled through cryptic prophecies. The infer keyword opens a portal to the hidden identities of types, adding an air of mystery to your code.

type InferReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function greet(): string {
  return "Greetings!";
}

type Greeting = InferReturnType<typeof greet>; // string
Enter fullscreen mode Exit fullscreen mode

Peer into the cryptic future with the power of type inference:

type Magic<T> = T extends infer U ? U extends string ? true : false : never;

type IsMagic = Magic<"abracadabra">; // true
Enter fullscreen mode Exit fullscreen mode

6. Key Remapping in Mapped Types: Unleashing the Shapeshifting Powers

Visualize a world where keys within your types can be reshaped, remolded, and reborn anew. Key Remapping in Mapped Types offers you the power to unlock shapeshifting abilities for your data structures.

type RenameKey<T, K extends keyof T, NewKey extends string> = {
  [P in keyof T as P extends K ? NewKey : P]: T[P];
};

interface Potion {
  name: string;
  duration: number;
}

type EnhancedPotion = RenameKey<Potion, "duration", "effectDuration">;
Enter fullscreen mode Exit fullscreen mode

Unleash the transformative force of key remapping:

type Coordinate = { x: number; y: number };
type Offset = { dx: number; dy: number };

function translate(coord: Coordinate, offset: Offset): Coordinate {
  return {
    x: coord.x + offset.dx,
    y: coord.y + offset.dy,
  };
}
Enter fullscreen mode Exit fullscreen mode

7. GlobalThis: Peering into the Global Horizon

Imagine gazing through a mystical window that grants you a view of the entire global realm. With GlobalThis, you can access the cosmic nexus of global objects, uniting the various threads of your code's reality.

const globalVar = 42;

console.log(GlobalThis["globalVar"]); // 42
Enter fullscreen mode Exit fullscreen mode

Harness the cosmic energy of GlobalThis in your own code realms:

declare global {
  interface Window {
    mysticalScroll: string;
  }
}

window.mysticalScroll = "Scroll of Ancient Wisdom";
Enter fullscreen mode Exit fullscreen mode

Conclusion

Thanks for joining me on this little journey, we will see if there will be more parts to this series. If you have any questions or feedback, feel free to reach out to me ^^

. . . . . . . . . . . . . . . . . . . . .