ThomasReggi
ThomasReggi

Reputation: 59485

Return type is non-null and based on input type

I am curious if it is possible to have one getOrFail function that does what I have below. As you can see the contents of both functions are the same, but the argument types are different.

export const getStringOrFail = (value: string | null, message: string = 'getStringOrFail error'): string => {
  if (value !== null) return value
  throw new Error(message);
}

export const getNumberOrFail = (value: number | null, message: string = 'getNumberOrFail error'): number => {
  if (value !== null) return value
  throw new Error(message);
}

I tried using a generic and returning that but then it's possible to return null.

How can I define one function that does what I have above?

Upvotes: 0

Views: 687

Answers (3)

lukasgeiter
lukasgeiter

Reputation: 153030

What you'll want to do is define a generic parameter, which doesn't include null:

export const getOrFail = <T extends string | number>(value: T | null, message: string = 'getOrFail error'): T => {
  if (value !== null) return value
  throw new Error(message);
}

Playground

As @jcalz suggested, if you want to go more generic and allow everything except null. You can use {} | undefined | void instead of string | number:

export const getOrFail = <T extends {} | undefined | void>(value: T | null, message: string = 'getOrFail error'): T => {
  if (value !== null) return value
  throw new Error(message);
}

Upvotes: 2

jcalz
jcalz

Reputation: 329533

Just to note another approach for completeness (it's not necessarily better than any of the others), using a conditional return type that Excludes null:

export const getOrFail = <T>(
  value: T | null,
  message: string = "getOrFail error"
) => {
  if (value !== null) return value as Exclude<T, null>;
  throw new Error(message);
};

And check how it behaves:

const bool = getOrFail(true); // boolean
const nevr = getOrFail(null); // never
const undef = getOrFail(undefined); // undefined
const strng = getOrFail(Math.random() < 0.5 ? "hello" : null); // string

That last one has a parameter of type string | null and the return type is Exclude<string | null, null>, or just string.

Link to code

Upvotes: 1

pneuma
pneuma

Reputation: 977

Try generic, but T should extend {}.

export function getOrFail<T extends {}>(value: T | null | undefined, message: string = "getNumberOrFail error"): T {
  if (value != null) return value;
  throw new Error(message);
}

{} allows everything except null or undefined.

More info here.

Upvotes: 2

Related Questions