Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Function that returns the same object shape as it accepted in typescript

I’d like to constrain a function such that it accept an object as an argument, and returns an object of the exact same shape. That object’s keys can be any string, and I’d like to tell typescript that the return object has the same keys. I.e.

interface ConstrainedObject {
  [key: string]: string[];
}

function transformer(argument: ConstrainedObject): ConstrainedObject {
  // ... code here
}

So really this function can accept an object whose keys are any string, but it should enforce that the return value has the same keys. I.e.

const result = transformer({
  linda: ['1', '2', '3'],
  jacob: ['4', '5', '6']
})

result.linda; // allowed, and intellisense should help here
result.jeremy // should error, as the object passed to transformer did not have this key

Is this possible in typescript?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

When you label something Record<string, string[]> or the mapped type you have you are saying specifically to the compiler that this object has a loose schema. Just don’t do that. Then you can combine the inferred type of the object with a generic constraint:

function transform<T extends Record<string, string[]>>(x: T): T {
    // modify x
    return x;
}

now when you call it

const x = transform({
  foo: ['a', 'b'],
});

you can reference x.foo and will compile, have autocompletion, etc. We have a type T that we know matches the schema you set but the compiler can infer a more specific type (in this case { foo: string[] }) for T.

If you want transform to be more general you can replace string[] with unknown in the generic constraint and it will work more generally, although for anything other than the identity function the implementation might get tricky.

function transform2<T extends Record<string, unknown>>(x: T): T {
  // modify x
  return x;
}

const y = transform2({
  a: true,
  b: 'hi',
  c: 5
});

const { a, b, c } = y;
console.log(a); // true
console.log(b.repeat(2)); // compiler knows it's a string, can call string method
console.log(c.toFixed(2)); // same for number here
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading