Getter function or default value for a typescript hashmap

Viewed 29

I am trying to write a simple getter for a value in an object with string keys or have some default of the same value type instead because I found myself needing to get values out of Maps many times. I assume this is a common pattern in Typescript. I am just looking for first level values no need to get nested data. It currently looks like this:

function getValueOrDefault<T>(
  object: Record<string, T>,
  path: keyof Record<string, T> & string,
  orDefault: T
): T {
  if (path in object && object[path] !== undefined) {
    return object[path] as T;
  } else {
    return orDefault;
  }
}

It seems like TypeScript infers in the object[path] that T could still be undefined even if I am already checking if object[path] !== undefined in the if block. Why is this happening? I have to cast with as T. Smells like a bad thing to do. Also can you get a better way to achieve what I am looking for?

1 Answers

The following would do the trick:

function getValueOrDefault<T extends object, P extends keyof T>(
  object: T,
  path: P,
  orDefault: T[P]
): T[P] {
  if (object[path] !== undefined) {
    return object[path];
  }
  return orDefault;
}

const a = getValueOrDefault({ a: '', b: 1}, 'a', 'default');
   // ^? const a: string

const b = getValueOrDefault({ a: '', b: 1}, 'b', 1 );
   // ^? const b: number

const obj: {c?: string} = {}
const c = getValueOrDefault(obj, 'c', 'default' );
   // ^? const c: string
Related