Recently, I was working on a TypeScript project where I needed to enforce type safety when accessing object properties. The challenge was to restrict access only to existing property keys of an object. That’s when I discovered the power of the keyof operator with string types.
In this article, I’ll share my experience using TypeScript’s keyof operator with strings and show you practical, real-world examples. If you’ve been struggling with type safety for object properties, this guide will help you implement robust solutions.
Let’s dive into TypeScript’s keyof operator and see how it can transform your code!
What is the keyof Operator in TypeScript?
The keyof operator in TypeScript takes an object type and produces a string or numeric literal union of its keys. It’s one of TypeScript’s most powerful features for working with object types.
Here’s a basic example:
interface User {
name: string;
age: number;
email: string;
}
// KeyType will be "name" | "age" | "email"
type KeyType = keyof User;
In this example, KeyType becomes a union type containing all property names from the User interface.
Check out Add Property to Object in TypeScript
Using keyof with String Types in TypeScript
Now let me show you the usage of keyof with string types in TypeScript.
Method 1: Basic Property Access with keyof
The most common way to use keyof with strings is to ensure type-safe property access:
interface Product {
name: string;
price: number;
category: string;
inStock: boolean;
}
function getProductProperty(product: Product, key: keyof Product): any {
return product[key];
}
const laptop = {
name: "MacBook Pro",
price: 1999,
category: "Electronics",
inStock: true
};
// This works
const productName = getProductProperty(laptop, "name");
// This would cause a TypeScript error
// const error = getProductProperty(laptop, "discount");
This pattern ensures that you can only access properties that actually exist on the object.
You can see the exact output in the screenshot below:

Check out Merge Object Arrays Without Duplicates in TypeScript
Method 2: Creating Type-Safe Record Objects
When creating objects where keys are restricted to certain string values, keyof becomes extremely useful. Here is an example and the complete code.
interface USState {
name: string;
capital: string;
population: number;
established: number;
}
const californiaData: USState = {
name: "California",
capital: "Sacramento",
population: 39538223,
established: 1850
};
type StateProperty = keyof USState;
// Create a record to track which properties have been updated
const propertyUpdated: Record<StateProperty, boolean> = {
name: false,
capital: false,
population: true,
established: false
};
This ensures that your record object only contains keys that match the original object structure.
Check out Merge Two Objects in TypeScript
Method 3: Generic Functions with keyof Constraints
For more flexible code, combine keyof with generics:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
interface Company {
name: string;
founded: number;
employees: number;
headquarters: string;
}
const apple: Company = {
name: "Apple Inc.",
founded: 1976,
employees: 154000,
headquarters: "Cupertino, CA"
};
// Type-safe property access
const companyName = getProperty(apple, "name"); // Returns string
const foundedYear = getProperty(apple, "founded"); // Returns number
console.log(companyName);
console.log(foundedYear);
This approach preserves the exact return type of each property, unlike our first method, which returned any.
You can see the exact output in the screenshot below:

Read Typescript merge two arrays of objects
Method 4: String Literal Types with keyof
You can combine string literal types with keyof for more precise type constraints. Here is an example.
interface USAddress {
street: string;
city: string;
state: string;
zipCode: string;
}
// AddressField will be "street" | "city" | "state" | "zipCode"
type AddressField = keyof USAddress;
// Only allow sorting by certain fields
function sortAddressesBy(addresses: USAddress[], field: AddressField & ("city" | "state")): USAddress[] {
return [...addresses].sort((a, b) => a[field].localeCompare(b[field]));
}
const addresses: USAddress[] = [
{ street: "123 Main St", city: "Boston", state: "MA", zipCode: "02108" },
{ street: "456 Pine Ave", city: "Miami", state: "FL", zipCode: "33101" }
];
// This works
const sortedByCity = sortAddressesBy(addresses, "city");
// This works
const sortedByState = sortAddressesBy(addresses, "state");
// This would cause a TypeScript error
// const sortedByStreet = sortAddressesBy(addresses, "street");
This pattern restricts the function to only accept certain properties for sorting.
Check out Typescript filter array of objects
Method 5: Type Mapping with keyof
You can create mapped types based on existing interfaces using keyof in TypeScript.
Below is an example.
interface UserProfile {
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
}
// Create a type for form validation errors
type ValidationErrors = {
[K in keyof UserProfile]?: string;
};
function validateUserProfile(profile: UserProfile): ValidationErrors {
const errors: ValidationErrors = {};
if (!profile.email.includes('@')) {
errors.email = "Invalid email address";
}
if (profile.phoneNumber.length < 10) {
errors.phoneNumber = "Phone number must be at least 10 digits";
}
return errors;
}
const newUser: UserProfile = {
firstName: "John",
lastName: "Doe",
email: "johngmail.com", // Missing @
phoneNumber: "555-123" // Too short
};
const validationResult = validateUserProfile(newUser);
console.log(validationResult);
// Output: { email: "Invalid email address", phoneNumber: "Phone number must be at least 10 digits" }
This creates a flexible validation system that automatically adapts to changes in the original interface.
Check out Typescript map object to another
Converting String to keyof Type
Sometimes you might receive a string from an external source (like user input or an API) and need to safely convert it to a keyof type:
interface TaxRates {
federal: number;
state: number;
local: number;
property: number;
}
const taxRates: TaxRates = {
federal: 0.22,
state: 0.05,
local: 0.01,
property: 0.015
};
function isTaxRateKey(key: string): key is keyof TaxRates {
return key === "federal" || key === "state" ||
key === "local" || key === "property";
}
function getTaxRate(key: string): number {
if (isTaxRateKey(key)) {
return taxRates[key];
}
throw new Error(`Invalid tax rate key: ${key}`);
}
// Usage with runtime safety
try {
const federalRate = getTaxRate("federal"); // Works fine
console.log(`Federal tax rate: ${federalRate * 100}%`);
// This would throw an error
// const invalidRate = getTaxRate("income");
} catch (error) {
console.error(error);
}
This approach provides runtime type safety when working with dynamic string values.
Here is the exact output in the screenshot below:

Read Typescript sort array of objects by date descending
Best Practices for Using keyof with Strings
Based on my experience, here are some best practices for working with keyof and string types:
- Use type guards for runtime safety: Always validate external string inputs before using them as object keys.
- Leverage union types with
keyof: Combinekeyofwith specific string literals for more precise type constraints. - Create helper functions: Encapsulate common property access patterns into reusable utility functions.
- Keep interfaces narrow: Design your interfaces only to include necessary properties to keep the resulting
keyoftypes manageable. - Use with mapped types: Combine
keyofwith mapped types to create powerful transformations of your data structures.
In this tutorial, I have explained how to work with TypeScript keyof with Strings.
TypeScript’s keyof operator can significantly improve type safety in your projects. By enforcing property access at compile time, you can prevent many common runtime errors.
If you’ve been struggling with maintaining type safety when accessing object properties, I hope these real-world examples help you implement keyof in your own code.
You may also like:

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.