Catharsis
Catharsis

Reputation: 657

Filter an object based on an interface

I've not managed to find a neat solution to this as yet and I feel there should be one but I don't quite have enough experience with Typescript to know it as yet. I hav an interface which defines some keys allowed in an object used for pagination

interface PaginationOptions {
  page: number;
  limit: number;
}

My input object is a HTTP query ?page=1&limit=3&name=Foo which translates to

{
  name: "Foo",
  page: 1,
  limit: 3,
}

What I want it to be able to make two objects from that, an object containing all the values of the keys defined in the interface and an object that has any other key. At the moment I am iterating through the incoming object and picking them apart manually but can't help but think there is a better way. Below is an example of the two objects I want to make from the above.

{
  page: 1,
  limit: 3
}

and

{
  name: "Foo"
}

Upvotes: 4

Views: 1445

Answers (1)

Moe
Moe

Reputation: 3713

The question boils down to this: "Is it possible to implement some javascript logic purely based on Typescript types?" And the short answer is "no", because the code will be compiled into javascript and the logic still needs to be specified somehow.

Let's take this code for example:

interface PaginationOptions {
  page: number;
  limit: number;
}

function makeTwoObjects<T extends PaginationOptions>(
  input: T
): {
  paginationOptions: PaginationOptions;
  otherOptions: Omit<T, keyof PaginationOptions>;
} {
  const { page, limit, ...otherOptions } = input;
  return {
    paginationOptions: { page, limit },
    otherOptions,
  };
}

The function is typed but we still needed to manually extract the properties we want from the object. Is there a way to avoid this?

When the code is eventually compiled to javascript, we will end up with a javascript function that simply receives an object and it's supposed to somehow select some properties from it.

So if we don't want to manually de-structure the properties, and if we want to avoid repeating the list of props multiple times, we still have to specify them at least once to the function in some other way. Like providing another argument, for example an array of the property names. You can use lodash.pick for this. Check this answer for more information.

This is one way of implementing it in typescript:

function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
  const ret = {} as Pick<T, K>;
  keys.forEach((key) => {
    ret[key] = obj[key];
  });
  return ret;
}

const input = {
  page: 10,
  limit: 20,
  foo: "bar",
};

const result = pick(input, "page", "limit");

console.log(result); 
// prints:
// {
//   "page": 10,
//   "limit": 20,
// };

Upvotes: 2

Related Questions