#Generic bag not inferring? --strictFunctionTypes
17 messages · Page 1 of 1 (latest)
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"]
...```
@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:
function test<X extends { a: unknown }>(prop: X["a"]) {return prop}
test("foo")
// ^? - function test<{
// a: unknown;
// }>(prop: unknown): unknown
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?
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:
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"
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
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.
Ah, this is what I was thinking of: https://github.com/microsoft/TypeScript/issues/54254
It seems like something similar is possible under the use cases section in that issue, but I don't 100% understand it yet
After a little bit more reading it seems keeping the multiple generics is the most straightforward I can find. Thanks again!