#Generic bag not inferring? --strictFunctionTypes

17 messages · Page 1 of 1 (latest)

simple widget
#

I have a fn which accepts a generic config bag as following. I would expect createBag works the same as createSimple, correctly inferring the types.

Is there a proper way to use a bag of generics like this?

Playground in comments

stoic anchorBOT
#
its.joshman#0

Preview:```ts
type BaseEnv = {x: 5}

// -------------- Ideal version --------------
interface DurableCfg<
TBaseEnv = unknown,
TInitalizedEnv = unknown

{
BaseEnv: TBaseEnv
InitalizedEnv: TInitalizedEnv
}
interface CreateBagProps<TCfg extends DurableCfg> {
initEnv: (
env: TCfg["BaseEnv"]
) => TCfg["InitalizedEnv"]
...```

vale mason
#

@simple widget Yeah, TS doesn't really have anywhere to infer a DurableCfg object from in your first version: the generic param itself isn't used anywhere, only properties of it.

#

When TS can't infer a prop, it defaults to its base constraint - in your case that's DurableCfg<unknown, unknown> so that's the result you get.

#

A simpler example that shows the same behavior:

stoic anchorBOT
#
function test<X extends { a: unknown }>(prop: X["a"])  {return prop}

test("foo")
// ^? - function test<{
//     a: unknown;
// }>(prop: unknown): unknown
simple widget
#

Hmm.. Is there a more correct way to create a single generic so I don't need to pass around a bunch of individual properties?

vale mason
#

I don't think so - I think keeping the two separate properties is best.

#

Introducing a 'wrapper' object adds complexity because the wrapper object doesn't have to necessarily just be those two properties.

#

e.g. going back to my simplified example, this is valid, but weird:

stoic anchorBOT
#
function test<X extends { a: unknown }>(prop: X["a"])  {return prop}

test<{a: 'foo', b: 'whatever'}>("foo")
// ^? - function test<{
//     a: 'foo';
//     b: 'whatever';
// }>(prop: "foo"): "foo"
simple widget
#

Hmm, thank you for the help! It's actually several more properties at multiple sites, which makes it pretty cumbersome to pass around by hand.

I'll do some reading on trpc because I think they use a similar strategy

vale mason
#

The other main alternative here is to make it generic on the whole env function:

#
interface CreateSimpleProps<EnvFunc extends (env: BaseEnv) => unknown> {
  initEnv: EnvFunc
}
function createSimple<EnvFunc extends (env: BaseEnv) => unknown>(props: CreateSimpleProps<EnvFunc> ) {
  return props.initEnv
}
const simple = createSimple({
  initEnv: (env) => env
})
#

This simplifies it to a single generic... but now the constraint on that generic is repeated and you have to use utilities to access the input and output types.

simple widget
simple widget
#

After a little bit more reading it seems keeping the multiple generics is the most straightforward I can find. Thanks again!