Typescript is very powerful in terms of type checking, but sometimes it gets tedious when some types are subsets of other types and you need to define type checking for them.
Let's take an example, you have 2 response types:
UserProfileResponse
interface UserProfileResponse {
id: number;
name: string;
email: string;
phone: string;
avatar: string;
}
LoginResponse
interface LoginResponse {
id: number;
name: string;
}
Instead of defining types of the same context LoginResponse and UserProfileResponse, we can define types for UserProfileResponse and pick some properties for LoginResponse.
type LoginResponse = Pick<UserProfileResponse, "id" | "name">;
Let's understand some utility functions that can help you to write better code.
Uppercase
Constructs a type with all properties of Type set to uppercase.
type Role = "admin" | "user" | "guest";
// Bad practice ๐ฉ
type UppercaseRole = "ADMIN" | "USER" | "GUEST";
// Good practice โ
type UppercaseRole = Uppercase<Role>; // "ADMIN" | "USER" | "GUEST"
Lowercase
Constructs a type with all properties of Type set to lowercase. Opposite of Uppercase.
type Role = "ADMIN" | "USER" | "GUEST";
// Bad practice ๐ฉ
type LowercaseRole = "admin" | "user" | "guest";
// Good practice โ
type LowercaseRole = Lowercase<Role>; // "admin" | "user" | "guest"
Capitalize
Constructs a type with all properties of the Type set to capitalize.
type Role = "admin" | "user" | "guest";
// Bad practice ๐ฉ
type CapitalizeRole = "Admin" | "User" | "Guest";
// Good practice โ
type CapitalizeRole = Capitalize<Role>; // "Admin" | "User" | "Guest"
Uncapitalize
Constructs a type with all properties of Type set to uncapitalize. Opposite of Capitalize.
type Role = "Admin" | "User" | "Guest";
// Bad practice ๐ฉ
type UncapitalizeRole = "admin" | "user" | "guest";
// Good practice โ
type UncapitalizeRole = Uncapitalize<Role>; // "admin" | "user" | "guest"
Partial
Constructs a type with all properties of Type set to optional.
interface User {
name: string;
age: number;
password: string;
}
// Bad practice ๐ฉ
interface PartialUser {
name?: string;
age?: number;
password?: string;
}
// Good practice โ
type PartialUser = Partial<User>;
Required
Constructs a type consisting of all properties of Type set to required. Opposite of Partial.
interface User {
name?: string;
age?: number;
password?: string;
}
// Bad practice ๐ฉ
interface RequiredUser {
name: string;
age: number;
password: string;
}
// Good practice โ
type RequiredUser = Required<User>;
Readonly
Constructs a type consisting of all properties of the Type set to read-only.
interface User {
role: string;
}
// Bad practice ๐ฉ
const user: User = { role: "ADMIN" };
user.role = "USER";
// Good practice โ
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = { role: "ADMIN" };
user.role = "USER"; // Error: Cannot assign to 'role' because it is a read-only property.
Record<K extends string, T>
Constructs a type with a set of properties K of type T. Each property K is mapped to the type T.
interface Address {
street: string;
pin: number;
}
interface Addresses {
home: Address;
office: Address;
}
// Alternative โ
type AddressesRecord = Record<"home" | "office", Address>;
Pick<Type, keys>
Pick only the properties of the Type whose keys are in the union type keys.
interface User {
name: string;
age: number;
password: string;
}
// Bad practice ๐ฉ
interface UserPartial {
name: string;
age: number;
}
// Good practice โ
type UserPartial = Pick<User, "name" | "age">;
Omit<Type, keys>
Omit only the properties of the Type whose keys are in the union type keys.
interface User {
name: string;
age: number;
password: string;
}
// Bad practice ๐ฉ
interface UserPartial {
name: string;
age: number;
}
// Good practice โ
type UserPartial = Omit<User, "password">;
Exclude<Type, Excluded>
Constructs a type with all properties of Type except for those whose keys are in the union type Excluded.
type Role = "ADMIN" | "USER" | "GUEST";
// Bad practice ๐ฉ
type NonAdminRole = "USER" | "GUEST";
// Good practice โ
type NonAdmin = Exclude<Role, "ADMIN">; // "USER" | "GUEST"
Extract<Type, Extract>
Constructs a type with all properties of Type whose keys are in the union type Extract.
type Role = "ADMIN" | "USER" | "GUEST";
// Bad practice ๐ฉ
type AdminRole = "ADMIN";
// Good practice โ
type Admin = Extract<Role, "ADMIN">; // "ADMIN"
NonNullable
Constructs a type with all properties of Type set to non-nullable.
type Role = "ADMIN" | "USER" | null;
// Bad practice ๐ฉ
type NonNullableRole = "ADMIN" | "USER";
// Good practice โ
type NonNullableRole = NonNullable<Role>; // "ADMIN" | "USER"
Thank you for reading ๐
Got any questions or additional? please leave a comment.
Must Read If you haven't
React best practices and patterns to reduce code - Part 1
React best practices and patterns to reduce code - Part 2
React.js state management using signals
useAsync hook with cache
More content at Hashnode.
Catch me on: Github, Twitter, LinkedIn, Medium, Dev.to, Blogspot, Stackblitz
ย