skip to Main Content

I’m trying to write a utility function in my TypeScript project to sort/filter objects in a fairly predictable data model (I’m using Astro for this site). The objects keep all the data useful for sorting/filtering in the data property.

I cannot figure out how to properly type this function, which takes a collection of objects and the name of a property as arguments: foo( collection, property ) { ... }.

Here’s a super simplified version of what I’ve been trying to do. It doesn’t take a collection as the first arg, but the gist is the same: I want to pass in the name of a property in data and then access the value of that property.

interface User {
  data: {
    id: number;
    name: string;
  }
}
interface House {
  data: {
    number: number;
    street: string;
  }
}
type Obj = User | House;

function getProperty<
  T extends Obj,
  K extends keyof T['data']
>(obj: T, key: K): T['data'][K] {
  return obj.data[key];
  // Type 'K' cannot be used to index type '{ id: number; name: string; } | { number: number; street: string; }'.ts(2536) 
}
const user: User = { data: { id: 1, name: "Alice" }};
const house: House = { data: { number: 2, street: "First" }};

const userName = getProperty(user, "name");
const houseNumber = getProperty(house, "number");

TypeScript understands what’s going on with the function, as the last two lines won’t let me pass in a property name that isn’t in the corresponding object’s data. But for the life of me, I don’t know how to get K to behave.

2

Answers


  1. Title: Type created with keyof cannot be used to index the type it was created from

    Body:
    I’m trying to write a utility function in TypeScript to access properties inside an object. Specifically, I want the function to:
    1. Take an object (of a known structure) as the first argument.
    2. Take the name of a property within data (from the object’s type) as the second argument.
    3. Return the value of that property, with TypeScript correctly inferring the type of the returned value.

    Login or Signup to reply.
  2. I’ve found that it often helps to play around with what exactly the generic type is. For example, this works:

    function getProperty<T, K extends keyof T>(
      obj: { data: T },
      key: K,
    ): T[K] {
      return obj.data[key];
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search