ZiiMakc
ZiiMakc

Reputation: 36826

Typescript function return type based on optional arguments

How can bad types be resolved?

TS sandbox.

interface X<T> {
    abc:T
}

declare function deepLock<Obj extends Record<string, any>,>(obj: Obj): X<Obj>;
declare function deepLock<Obj extends Record<string, any>,>(obj: Obj, options: {}): X<Obj>;
declare function deepLock<
  Obj extends Record<string, any>,
  Action extends "freeze" | "seal" | "preventExtensions",
  Options extends { action?: Action }
>(obj: Obj, options?: Options): Action extends 'freeze' ? X<Obj> : Obj

// ok
const x = deepLock({}) // expect X<{}>
const x2 = deepLock({}, {}) // expect X<{}>

// need to be fixed
const x3 = deepLock({}, {action: 'freeze'}) // expect X<{}>
const x4 = deepLock({}, {action: 'seal'}) // expect Obj
const x5 = deepLock({}, {action: 'preventExtensions'}) // expect Obj

Upvotes: 0

Views: 102

Answers (1)

zecuria
zecuria

Reputation: 778

So you just need to adjust your function definition very slightly to:

declare function deepLock<
  Obj extends Record<string, any>,
  Action extends "seal" | "preventExtensions" | "freeze",
>(obj: Obj, options?: { action?: Action }): 'freeze' extends Action ? X<Obj> : Obj;

The problem you are facing is that Action is extending "seal" | "preventExtensions" | "freeze" and so by definition Action extends "freeze" will always be true as it always extends that.

So in order to correctly narrow the types you have to do "freeze" extends Action which will only ever be true for one of the three possibilities for Action.

Playground link

Hope that makes sense

Upvotes: 1

Related Questions