mapped-types
Mapped Types in TypeScript:
Certainly! Here are some concise TypeScript code examples illustrating each key point about mapped types:
Introduction to Mapped Types:
Mapped types enable you to create new types by transforming all properties of an existing type into new types, offering a flexible way to represent state variations without duplicating types.
- Example:
// Original interface
interface Person {
name: string;
age: number;
}
// Mapped type that makes all properties optional
type PartialPerson = {
[Property in keyof Person]?: Person[Property];
};
Basics of Creating Mapped Types:
Mapped types use a syntax akin to a for-loop to iterate over properties of an existing type and can modify their names and types in the new mapped type.
- Example:
// Mapped type that prefixes all property names with 'new_'
type PrefixedProperties<T> = {
[Property in keyof T as `new_${string & Property}`]: T[Property];
};
Using keyof with Mapped Types:
The keyof
operator is used in mapped types to generate a union of property names from an existing type, which is then iterated over in the mapped type.
- Example:
// Mapped type that creates a union of property names
type PropertyNames = keyof Person; // "name" | "age"
Modifying Property Types:
Mapped types can be used to change the property types of an existing type, such as converting all properties of an interface from one type to another.
- Example:
// Mapped type that changes all property types to strings
type StringifiedProperties<T> = {
[Property in keyof T]: string;
};
Adding Modifiers to Properties:
Mapped types can also add or remove modifiers, allowing you to make all properties of a type readonly
or optional.
- Example:
// Mapped type that makes all properties readonly
type ReadonlyProperties<T> = {
readonly [Property in keyof T]: T[Property];
};
Using in with Mapped Types:
The in
keyword is used within mapped types to iterate over the keys of a union created by keyof
.
- Example:
// Mapped type that transforms all properties to nullable
type NullableProperties<T> = {
[Property in keyof T]: T[Property] | null;
};
These examples showcase the versatility of mapped types in TypeScript, allowing developers to create new types based on existing ones with precision and control.
- Utility Types as Mapped Types:
TypeScript's utility types like Partial<T>
and Readonly<T>
are practical examples of mapped types that make all properties of T
optional or readonly.
interface Task {
id: number;
description: string;
}
type OptionalTask = Partial<Task>;
type ImmutableTask = Readonly<Task>;
- Conditional Types with Mapped Types:
Combine mapped types with conditional types to create types that change based on certain conditions.
type ConditionalProperties<T> = {
[P in keyof T]: T[P] extends Function ? P : never;
};
- Template Literal Types with Mapped Types:
Template literal types within mapped types allow you to manipulate property names.
type MappedWithTemplateLiterals<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]
};
- Using Mapped Types for Defaults:
Mapped types can set default types for properties, establishing default states for types.
type Defaults<T> = {
[P in keyof T]?: T[P] extends Required<T>[P] ? T[P] : never;
};
- Filtering Properties with Mapped Types:
Mapped types can filter which properties to include or exclude, analogous to filtering array elements.
type PickTask = Pick<Task, 'description'>; // Only the description property
type OmitTask = Omit<Task, 'id'>; // All except the id property
- Mapped Types with Index Signatures:
Apply transformations to index signatures in types using mapped types.
type IndexSignatureMapped<T> = {
[P in keyof T]: T[P] extends infer R ? R : never;
};
- Combining Mapped Types:
Compose multiple mapped types to create intricate type transformations.
type CombinedMapped<T> = Readonly<Partial<T>>;
- Advanced Techniques with Mapped Types:
Mapped types can be combined with generics or type inferences for advanced and versatile type manipulations.
type AdvancedMapped<T> = {
[P in keyof T]: T[P] extends infer U ? { prop: U } : never;
};
- Performance Considerations:
Use mapped types considerately to balance their compile-time impact and complexity in the codebase.
// Example omitted for brevity - consider performance impacts when designing types.