0

Suppose I have the following interface:

interface Foo {
  x: {
    x1: string;
    x2: {
       x3: number; 
    }
  };
}

I want to write a class where a function automatically figures out the valid arguments based on the type.

For example:

const x = someNewClass();
x
 .ref('x')
 .ref('x1 | x2') // we pass either x1 or x2
 .ref('x3').getAsPath(); // if we pass x2, we see x3, otherwise undefined

The values I've written should auto-complete, and the function should return the path: x/x2/x3';

I don't know typescript very well -- I don't even know if this is possible! However, I got this far (which admittedly isn't very far):

class SomeHelperClass<T> {
  public ref(d: keyof T) {
    // can we return a new instance of a this class initialized with
    // T taken as a partial of the original type starting from `d`?
    return this;
  }
  public getAsPath() {
    // ...
  }
}

class Test extends SomeHelperClass<Foo> {}

const t = new Test();

t.ref('x').ref('...');

The first ref call of course works, but I am completely lost after that.

1

1 Answer 1

1

Thanks to @SergiuParaschiv's link, I found a working solution for my exact issue. I am sharing the code here in case the github repos or the references disappear for any reason.

interface PathResult<T> {
    <TSubKey extends keyof T>(key: TSubKey): PathResult<T[TSubKey]>;
    /**Gets the resulting path */
    path: string[];
}

/**
 * Create a deep path builder for a given type
 */
export function path<T>() {
    /**Returns a function that gets the next path builder */
    function subpath<T, TKey extends keyof T>(parent: string[], key: TKey): PathResult<T[TKey]> {
        const newPath = [...parent, key];
        const x = (<TSubKey extends keyof T[TKey]>(subkey: TSubKey) => subpath<T[TKey], TSubKey>(newPath, subkey)) as PathResult<T[TKey]>;
        x.path = newPath;
        return x;
    }

    return <TKey extends keyof T>(key: TKey) => subpath<T, TKey>([], key);
}

To see the solution in action, please visit the author's repository.

Thanks again Sergiu!

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

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.