[SOLVED] Typesafe nested property lookup

Issue

I am trying to create a type safe version of the get lodash function (see here). My idea is to create a function that is able to return the correct type if the nested property is available otherwise undefined.

interface Nested {
  value: 'some' | 'type';
}
interface SomeComplexType {
  foo: string;
  bar: number;
  nested: Nested;
}

const testObject: SomeComplexType = {
  foo: 'foo value',
  bar: 1234,
  nested: {
    value: 'type'
  }
};

// The type of someValue should be: 'some' | 'type'
const someValue = lookup(testObject, 'nested.value');
console.log('Value found:', someValue);

Right now I have the following:

function get<T, K extends keyof T>(object: T, key: K): T[K] | undefined {
  return object[key];
}

function lookup<T, K extends keyof T>(object: T, path: string) {
  const parts = path.split('.');
  const property = parts.shift() as K; // TODO autoinfer is possible?
  const value = get(object, property);

  if (!parts.length || value === undefined) {
    return value;
  }

  const newPath = parts.join('.');
  return lookup(value, newPath);
}

But I am stuck with the lookup return type. Typescript in strict mode says:

src/lookup.ts:14:10 – error TS7023: ‘lookup’ implicitly has return
type ‘any’ because it does not have a return type annotation and is
referenced directly or indirectly in one of its return expressions.

Any ideas?

Solution

Answering my own question after the introduction of template literal types.

Now with template literal types you can obtain exactly what I wanted.

See example in playground.

See here for the implementation (from this tweet):
https://github.com/ghoullier/awesome-template-literal-types#dot-notation-string-type-safe

So now it works (I renamed the function from get to lookup)
Working solution

Answered By – Volox

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *