I gathered several cases with the results, please review them and If you agreed fix the typings according to.
interface FooBar {
readonly required: string;
readonly optional?: string;
}
const requiredFoobar: FooBar = {} as any;
const optionalFoobar: undefined | FooBar = {} as any; // Do not define object here, because TS use that instead of the type definitions
const returnsString = propOr('required', 'required', requiredFoobar);
const shouldNotCompile = propOr(undefined, 'required', requiredFoobar); // because the property is required, and the input object is present
const returnsString = propOr('optional', 'optional', requiredFoobar); // when we define the default value it must return with a T type
const returnsStringOrUndefined = propOr(undefined, 'optional', requiredFoobar); // when the output can be undefined than it must return a type T | undefined
const returnsString = propOr('required', 'required', optionalFoobar);
const returnsStringOrUndefined = propOr(undefined, 'required', optionalFoobar);
const returnsString = propOr('optional', 'optional', optionalFoobar);
const returnsStringOrUndefined = propOr(undefined, 'optional', optionalFoobar);
// Should not compile in case of type mismatch
const shouldNotCompile = propOr(1, 'required', requiredFoobar);
const shouldNotCompile = propOr(1, 'optional', requiredFoobar);
const shouldNotCompile = propOr(1, 'required', optionalFoobar);
const shouldNotCompile = propOr(1, 'optional', optionalFoobar);
// Should not compile in case of key is not in the object
const shouldNotCompile = propOr('', 'foo', requiredFoobar);
const shouldNotCompile = propOr('', 'foo', optionalFoobar);
I also tried to fix the type definition, it is the best I could do:
type PropOrValue<T, K extends keyof NonNullable<T>> = T extends NonNullable<T> ? NonNullable<T>[K] : NonNullable<T>[K] | undefined
/**
* It returns either `defaultValue` or the value of `property` in `obj`.
*/
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: NonNullable<NonNullable<T>[K]>, property: K, obj: T): NonNullable<NonNullable<T>[K]>;
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: PropOrValue<T, K>, property: K, obj: T): PropOrValue<T, K>;
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: NonNullable<NonNullable<T>[K]>, property: K): (obj: T) => NonNullable<NonNullable<T>[K]>;
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: PropOrValue<T, K>, property: K): (obj: T) => PropOrValue<T, K>;
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: NonNullable<NonNullable<T>[K]>): FunctionToolbelt.Curry<(property: K, obj: T) => NonNullable<NonNullable<T>[K]>>;
export function propOr<T, K extends keyof NonNullable<T>>(defaultValue: PropOrValue<T, K>): FunctionToolbelt.Curry<(property: K, obj: T) => PropOrValue<T, K>>;
I gathered several cases with the results, please review them and If you agreed fix the typings according to.
I also tried to fix the type definition, it is the best I could do: