9

Suppose there is an interface

interface A {
  a: number;
}

and currently I have a raw object

const a = { a: 1, b: '2' };

I expect a way to get x to be { a: 1 }, which contains only members defined in interface.

This can be achieved through creating an empty {} and looping over and filling in all A's members, but considering interface members and object's redundant fields can be up to dozens, it is not practical to do so.

I tried

let x = <A> a; // or let x = a as A;
console.log((x as any).b); // still exist

I also looked up in lodash and found keys and pick, but these are targeted for class instance instead of interface.

4
  • 2
    This is not "casting", which doesn't even exist in TS. It's "picking". Commented Jun 14, 2017 at 6:24
  • @Mike it's not clear what you want to achieve. ts duck typing let downcast the type of a to A and with typescript editors you can access only to members of A but the real object is always of type a. Because ts type erasure implies that objects are of type Object at runtime you see the whole a. If you want another object you have to copy its properties (like pick solution suggests). Instead if you want a compile time check use A and don't worry about what the real object is. Commented Jun 14, 2017 at 7:10
  • @Aris2World I have an interface definition and would like to convert an object with redundant fields to it. In addition, I do not want to explicitly state the fields to pick. Commented Jun 14, 2017 at 8:35
  • @Mike maybe there is a misconception about object and type (what an interface represent). Suppose you have also this interface B { b: string; }. You can treat the object a as an object of type both A and B: let x: A = a you can access members of A or let x: B = a you can access members of B. The object a is of type Object which is the only one existing in javascript. Commented Jun 14, 2017 at 12:10

2 Answers 2

4

Interfaces don't exist at runtime. Your best option would be delete unwanted properties yourself or create a copy of the object with the properties you need.

For example you can use a method like this (method copied from this answer):

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

    keys.forEach(key => copy[key] = obj[key]);

    return copy;
}

const a = { a: 1, b: '2' };
let copy : A = pick(a, "a");
console.log(copy);
Sign up to request clarification or add additional context in comments.

3 Comments

Good. Add only that if he wants to have a variable of type A he can write let x: A = pick(a, "a")
how can i provide "a"? can i get it from definition of interface?
@Mike No. It has to be from a value present after compilation. If you want to get the keys of an interface, you can take a look at this library suggested by Amid. But looking at the source code of that library (it reads the syntax tree of the program), it might be a bit too much.
2

Basically your question boils down to the problem of getting all properties of the interface as an array of strings and then make an copy of the object containing only those properties. Making a copy of object is pretty simple and there are tons of examples out there. But the first issue is much harder to tackle.

As far as I know the only way to get this done "now" is to use custom transformers for typescript during compilation. Here is an example, but please note - this require to use typescript 2.4+ that is not yet in stable release.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.