Maciek Leks
Maciek Leks

Reputation: 1448

Proxy with mapped types

I walk through TS Handbook and I came to the mapped types. There is a code snippet to wrap object property into proxy.

type Proxy<T> = {
    get(): T;
    set(value: T): void;
}
type Proxify<T> = {
    [P in keyof T]: Proxy<T[P]>;
}
function proxify<T>(o: T): Proxify<T> {
   // ... wrap proxies ...
}
let proxyProps = proxify(props);

I'm trying to fill the gap in the proxify function with my implementation of it, and I get something like this:

function proxify<T>(t: T): Proxify<T> {
    let result = <Proxify<T>>{};
    for (const k in t) {
      result[k] = {    //(*) from that moment I lose strong typing  
        get: () => t[k],
        set: (value) => t[k] = value
      }
    }
    return result;
  }

I can't control types inside the loop and everything must by of any type there. How to cope with that, assuming that my implementation is correct at all?

Upvotes: 2

Views: 1274

Answers (2)

Namig Hajiyev
Namig Hajiyev

Reputation: 1541

My version of implementation is as below. I couldn't find a way to force type safety in get and set. It could be more elegant if there was some way to write properties like this get():PropType , set(value:PropType)

function proxify<T>(o: T): Proxify<T> {
        const proxifyObj: Proxify<T> = <Proxify<T>>{};
        Object.keys(o).map((key) => {
            proxifyObj[key] = {
                get() {
                    return o[key];
                },
                set(value) {
                    o[key] = value;
                }
            };

        });
        return proxifyObj;
    }

Upvotes: 1

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249696

The implementation seems ok. While creating the object there is some safety lost but you don't loose it all. The amount of typing you still get might actually surprise you

function proxify<T>(t: T): Proxify<T> {
    let result = <Proxify<T>>{};
    for (const k in t) { // k is of type Extract<keyof T, string> so it must be a key of T
        // result[k] and t[k] both work because k is a key of both T and Proxify<T> but result['random'] would be invalid
        result[k] = { // get/set fields are checked, so _get would be an error
            // the return of get must be T[Extract<keyof T, string>] so ()=> 0 would be an error
            get: () => t[k],
            // value and t[k] must be T[Extract<keyof T, string>] so t[k] = '' would also be an error
            set: (value) => t[k] = value
        }
    }
    return result;
}

Upvotes: 5

Related Questions