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 argument type inference and conditional type

I’m trying to cover following case:

I have a function which accepts a boolean and returns value of RealItem | ImaginaryItem type. I’m using conditional type to narrow the return type based on boolean argument.

type RealItem = { color: string }
type ImaginaryItem = { description: string }

export function createItem<T extends boolean>(isReal: T): T extends true ? RealItem : ImaginaryItem

export function createItem<T extends boolean>(isReal: T): RealItem | ImaginaryItem {
  return isReal ? { color: 'red' } : { description: 'Crazy thing' }
}

My signatures seem to be working fine for following cases:

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

const a = createItem(true)      | typeof a -> RealItem
const b = createItem(false)     | typeof b -> ImaginaryItem


let isReal = true
const a = createItem(isReal)    | typeof a -> RealItem

let isReal = false
const b = createItem(isReal)    | typeof b -> ImaginaryItem

However if I wrap createItem into another function and pass isReal argument:

const itemsFactory = (isReal: boolean) => createItem(isReal)

TS seems to fail to deduct return type narrowed with conditional return type:

const a = itemsFactory(true)    | typeof a -> RealItem | ImaginaryItem
const b = itemsFactory(false)   | typeof b -> RealItem | ImaginaryItem

TS playground

I’m not gonna lie, the union type makes me very unhappy.

  • Is this some sort of limitation of TS capabilities in type interference?
  • Can I help TS understand how to interpret higher function arguments?

I know I could use type guards here, however they don’t go well with my current code structure.

>Solution :

The type information of isReal is essentially lost with the itemsFactory function since you specified isReal as a boolean here.

To fix this, you can also add the same generic type to the itemsFactory function:

const itemsFactory = <T extends boolean>(isReal: T) => createItem(isReal)

Playground

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