#.

1 messages ยท Page 1 of 1 (latest)

mellow scroll
#

๐Ÿ‘‹

#

can you share enough of your code to demonstrate the problem? it all comes down to details you haven't provided (like what cart is). for example i stubbed out the missing stuff here and it works the way you hoped:

true sparrowBOT
#
mkantor#0

Preview:```ts
// i made these up:
type ProductCode = 'a' | 'b'
const cart = {
get: () => ({ a: 42 })
}

// ---

export type CartValue = {
[key in ProductCode]?: number;
};

function forProductInCart<T extends CartValue>(
cart: T,
callback: (key: keyof T, value: T[keyof T]) => void
...```

mellow scroll
#

what's the return type of cart.get in your code?

#

well there's your problem. CartValue is as general as it gets. keyof CartValue is always going to be the entirety of ProductValue

#

you need to be operating with a more specific subtype of CartValue

#

like in my example how the return type is inferred as { a: number }

#

this would really be easier to talk about if you can share your complete code

#

(or at least a made-up approximation that has enough detail to capture the important stuff)

#

i suspect that's not quite what you have, because there's a type error before we even get to the type of value (Property 'get' does not exist on type 'CartValue'):

true sparrowBOT
#
mkantor#0

Preview:```ts
type ProductCode = "a" | "b"

export type CartValue = {
[key in ProductCode]?: number
}

// could be any valid CartValue, not literally this
const cart: CartValue = {
a: 1,
b: 2,
}

function forProductInCart<T extends CartV
...```

mellow scroll
#

thanks

#

so the first thing to be aware of is that what you're doing is inherently unsafe. it's why you had to use a type assertion on keys

#

!:unsafe-keys

true sparrowBOT
#
retsam19#0
`!retsam19:unsafe-keys`:

Since TS allows objects to have extra properties not specified in the type, it doesn't assume that all the keys on the type are the only keys on the object. This means that Object.keys returns string[] not a specific type, and for(const key in obj), key is string, (not keyof typeof obj).

If you wish to assume otherwise, this utility is often helpful:

// A signature for `Object.keys` that assumes the only keys are the ones indicated by the type
const unsafeKeys = Object.keys as <T>(obj: T) => Array<keyof T>;
mellow scroll
#

but if you understand that and are okay with this kind of unsafety, i think it'd be possible to subtract out optional keys of T in the signature of forProductInCart. but i don't think that's what you want either, because if cart is really typed as exactly CartValue then that is always just going to be never (because CartValue says that every property is optional)

#

so tl;dr at the end of the day cart needs to have a more specific type like i said earlier

#

i might be missing something though. your question doesn't quite make sense to me on a conceptual level. how would the compiler ever be able to know exactly what keys are present at runtime in the case where you have a value that is an arbitrary CartValue? if that's not what you're asking maybe you can rephrase the question

#

the "values actually present" part is i think where our confusion lies, but what do you think of a dumber setup like this?

true sparrowBOT
#
mkantor#0

Preview:```ts
type ProductCode = "a" | "b"

export type CartValue = {
[key in ProductCode]?: number
}

declare const cart: CartValue

function forProductInCart(
cart: CartValue,
callback: (
key: keyof CartValue,
value: number
) => void
): void {
const keys = Object.keys(cart) as Array<
...```

mellow scroll
# true sparrow

note that that's still unsafe for the same reason i mentioned above

#

here's a safe version in case you care about that โ˜๏ธ:

true sparrowBOT
#
mkantor#0

Preview:```ts
const allPossibleCartKeys = ["a", "b"] as const
type ProductCode = typeof allPossibleCartKeys[number]
// ^?

export type CartValue = {
[key in ProductCode]?: number
}

declare const cart: CartValue

function forProductInCart(
cart: CartValue,
callback: (
key: keyof CartValue,
v
...```

mellow scroll
#

you're welcome ๐Ÿ™‚