Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to take a subset of an object using an interface?

Suppose I have this class and interface

class User {
    name: string;
    age: number;
    isAdmin: boolean;
}

interface IUser {
    name: string;
    age: number;
}

And then I get this json object from somewhere

const data = {
    name: "John",
    age: 25,
    isAdmin: true
}

I want to subset data using IUser and remove the isAdmin property like this

let user = subset<IUser>(data);
// user is now { name: "John", age: 25 }
// can safely insert user in the db

My question is how do I implement that function in TypeScript?

function subset<T>(obj: object) {
    // keep all properties of obj that are in T
    // keep, all optional properties in T
    // remove any properties out of T
}
like image 661
Bosak Avatar asked Mar 26 '17 11:03

Bosak


1 Answers

There's no way to do that which is better than:

function subset(obj: IUser) {
    return {
        name: obj.name,
        age: obj.age
    }
}

The typescript interfaces don't exist at runtime (which is when subset is invoked) so you cannot use the IUser interface to know which properties are needed and which aren't.

You can use a class which does "survive" the compilation process but:

class IUser {
    name: string;
    age: number;
}

Compiles to:

var IUser = (function () {
    function IUser() {
    }
    return IUser;
}());

As you can see, the properties aren't part of the compiled output, as the class members are only added to the instance and not to the class, so even a class won't help you.

You can use decorator and metadata (more on that here) but that sounds like an overkill for your scenario.

Another option for a more generic subset function is:

function subset<T>(obj: T, ...keys: (keyof T)[]) {
    const result = {} as T;

    keys.forEach(key => result[key] = obj[key]);
    return result;
}
let user1 = subset(data, "name", "age");
let user2 = subset(data, "name", "ag"); // error: Argument of type '"ag"' is not assignable to parameter of type '"name" | "age" | "isAdmin"'
like image 92
Nitzan Tomer Avatar answered Nov 16 '22 04:11

Nitzan Tomer