Narrow inferred type when function has explicit return

Viewed 62

Look at the following code:

type Shape = null | string | string[] | { [key: string]: string | string[] }

interface ICfg<InShape extends Shape, OutShape extends Shape> {
  shapes?: readonly [InShape, OutShape]
  handle?(x: NonNullable<this["shapes"]>[0]): NonNullable<this["shapes"]>[1]
}

function apply<InShape extends Shape, OutShape extends Shape>(cfg: () => ICfg<InShape, OutShape>) {
  return cfg()
}

const shape = {
  type: "abc",
  date: "qwe",
}

var x = apply(() => ({
  shapes: [shape, shape],
  handle: x => null as any,
}))

Type of variable x is ICfg<{ type: string; date: string; }, { type: string; date: string; }> and that's perfect.

But let's change function syntax a bit: from () => ({ ... }) to () => { return { ... } }:

var y = apply(() => {
  return {
    shapes: [shape, shape],
    handle: x => null as any,
  }
})

Now type of y is ICfg<Shape, Shape> and that's bad.

Actually I have a bit more difficulties as I really need variable shape to be inside of the function (in reality function apply has arguments and shape is based on them):

var z = apply(() => {
  const shape = {
    type: "abc",
    date: "qwe",
  }

  return {
    shapes: [shape, shape],
    handle: x => null as any,
  }
})

This code produces same ICfg<Shape, Shape> for variable z.

I need variable z to have type ICfg<{ type: string; date: string; }, { type: string; date: string; }> like x does. Is there any way to achieve that without explicit specifying generic parameters of apply?

Full code in the playground.

0 Answers
Related