Day 40: keyof
Tags: day40, javascript, typescript, 100daysofcode
Published: 2023-09-04 13:30:00


### What is `keyof`?

The `keyof` operator in TypeScript is used to create a union type of all the property names (keys) of an object type. This union type can then be used to define and enforce type constraints within your code.

```typescript
type KeyOfDemo = keyof { name: string; age: number }; // "name" | "age"
```

### How does it work?

When applied to an object type, `keyof` generates a union type comprising all the keys of that object's properties. This union type can be used for various purposes like indexing, type-checking, and creating more precise type definitions.

## 2. Practical Use Cases

### Type-Safe Object Access

One of the most common use cases for `keyof` is enabling type-safe object access. Consider a scenario where you have an object representing a person:

```typescript
const person = {
  name: "John",
  age: 30,
  city: "New York",
};
```

By using `keyof`, you can create a type that ensures you only access valid properties:

```typescript
type Person = typeof person;
type PersonKeys = keyof Person; // "name" | "age" | "city"
```

Now, you can access `person` properties safely:

```typescript
function getProperty(obj: Person, key: PersonKeys): any {
  return obj[key];
}

const name = getProperty(person, "name"); // ✅ Type-safe
const invalid = getProperty(person, "gender"); // ❌ Compile-time error
```

### Enforcing Property Keys

You can also use `keyof` to enforce that an object contains specific keys:

```typescript
function hasRequiredKeys(obj: Person, keys: ["name", "age"]): boolean {
  return keys.every(key => key in obj);
}

const hasKeys = hasRequiredKeys(person, ["name", "age"]); // ✅ true
const missingKey = hasRequiredKeys(person, ["name", "gender"]); // ❌ false
```

### Function Parameter Validation

`keyof` can be a valuable tool for validating function parameters, ensuring only valid keys are accepted:

```typescript
function updatePerson(obj: Person, key: PersonKeys, value: any): void {
  obj[key] = value; // ✅ Type-safe
}

updatePerson(person, "age", 31); // ✅
updatePerson(person, "gender", "Male"); // ❌ Compile-time error
```

## 3. Advanced Techniques

### Combining `keyof` with Other Operators

You can combine `keyof` with other TypeScript operators for even more powerful type definitions. For example, using `keyof` with `typeof` to create a mapped type:

```typescript
type OptionalPerson = {
  [K in keyof Person]?: Person[K];
};
```

### Generics and `keyof`

Generics and `keyof` can be used together to create flexible and reusable type-safe functions:

```typescript
function getPropertyByKey<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const cityName = getPropertyByKey(person, "city"); // ✅ Type-safe
```

## 4. Common Pitfalls and Best Practices

### Avoiding String Literals

Avoid using string literals when working with `keyof` to maintain type safety:

```typescript
const prop = "age";
const age = person[prop]; // ❌ No type checking
```

### Type Narrowing

Remember that `keyof` unions need to be narrowed down for conditional checks:

```typescript
type KnownKeys = "name" | "age";
function isKnownKey(key: string): key is KnownKeys {
  return ["name", "age"].includes(key);
}
```

### Keyof in Libraries

When working with external libraries, be cautious about assuming property keys. Libraries might use techniques like symbol-based keys, which `keyof` might not cover.