You can use a mapped type to fetch the nested type:
type KnownOptions<T> = T extends {
[k in keyof T]: {
[k: string]: infer OptionValue
}
} ? OptionValue : never
// Good:
const a: KnownOptions<Options> = { foo: 'bar' }
const b: KnownOptions<Options> = { baz: 'daz' }
// Expect errors:
const c: KnownOptions<Options> = { foo: 'bad value' }
const d: KnownOptions<Options> = { badKey: 'bar' }
Playground
This is a generic type that accepts a type that has two levels of keys. The conditional type (noted by the ternary T extends Type ? A : B
) says "if the generic type T is an object at least 2 level deeps, then return the type at each of those that second levels. Else, return the never
type, because the generic type is invalid.
The infer OptionalValue
says "whatever type is here, save that as OptionValue
". This is then returned by the conditional type, after multiple type have been saved to it, creating a union of each type.
I have to admit, I'm not entire sure why the first level key needed to be k in keyof T
but the second level could just be k: string
. But, that was the only way I got it to work properly.