1

I have the following interfaces:

interface TxInterface {
    field1: string;
    field2: string;
    field3: number;
}

interface RxInterface {
    field1: string;
    field2: string;
    field3: number;
    field4: string;
    field5: string;
}

When I receive an object from server, it is typed with RxInterface. In my App, I continue to use this object when I update values for instance.

When I would like to update object in server, I shall send "TxInterface", that contains some fields of "RxInterface".

So, how can I easily to merge my object from RxInterface to TxInterface before send and take only the fields of TxInterface?

4

2 Answers 2

1

There's no way to do this merely with the interface definitions, since such definitions are part of the type system which is erased by runtime. If you need something done at runtime, you need to write code which does it at runtime. In this case, here's a generic function which extracts just the properties of an object matching a list of keys:

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

And for your specific use case, you can make a conversion function whose types involve RxInterface and TxInterface, but which specifies the particular keys you care about as values and not types:

const rxToTx = (rx: RxInterface): TxInterface => // type annotation here
    extract(rx, ["field1", "field2", "field3"]); // explicit key values here

And you can verify that it works:

const rx: RxInterface = {
    field1: "yes",
    field2: "yep",
    field3: 100,
    field4: "no",
    field5: "nope"
}

const tx = rxToTx(rx);

console.log(tx);
// {field1: "yes", field2: "yep", field3: 100}

Hope that helps; good luck!

Sign up to request clarification or add additional context in comments.

4 Comments

Your solution works but warnings are raised and I can't find a solution. The head warning is "Argument type [string , string , string] is not assignable to parameter type keyof T[] ". I works with PhpStorm.
Uh, I can't reproduce your issue. If you are using TS3.4+ you can try ["field1", "field2", "field3"] as const, but I think it should work as stated. Do you have a way of producing a minimal reproducible example which demonstrates your problem? If I can't reproduce it it's hard to give advice.
I use TS3.2 in Angular 7 app. Minimal example can be "Create Angular 7 project" then "Add the snippets in app.component.ts"
I don't have PhpStorm, so unless your example can be reproduced via a link to some web IDE like this or this, I don't think I can be of much help here. And if you suspect that your issue is specific to PhpStorm, you should add that tag to your question... (maybe a new question, since I doubt you'll get much eyes on this one if you just edit it)
0

All right. It is a good starting point to introduce binary operations also known as "reductions".

Consider generic function signature: T -> T -> T. What it does is takes two parameters of the same type T and somehow "collapses" them into a single resulting instance of the same type T. As a trivial example, take + on numbers or concatenation on the strings.

It turns out that such a binary operation is unbelievably common across various branches of math and founded on a much more reliable reasons then just a programming convenience. For example, a "semigroup" is essentially the same binary operation with few additional properties, I won't explain here.

So, don't ignore it. Rather design you code in such a way that you can leverage binary operations of the abovementioned (generic) signature. The question is: how? Mapping! Have you ever heard something about "map/reduce" approach? That's exactly what you are about to implement: firstly map a non-reducible instance into a reducible one and then apply one of reductions you have in order to compute final result.

P.S. In your case mapping since to be trivial: just specify explicitly generic params, since a wider interface is also satisfies narrower interface.

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.