What i want
I have a type with known values
type Possibilities = "a" | "b" | "c"
And want to be able to create object that can only have keys that belongs to that type, but not necessarily all of then.
And also prevent each prop's type from outputing as string | undefined
As it is meant to be used on constants, that have fixed values. And TS can already infer proper typing:
So, it should accept:
const mine = {
a: "this",
b: "and",
c: "that"
}
const yours = {
b: "it"
}
But should not:
// not known key ( 'x' )
const theirs = {
a: "these",
x: "those"
}
// preferably - empty object
const noOnes = {}
I've tryed:
If i do one of bellow
const mine: Record<Possibilities, string>; const mine: {[key in Possibilities]: string};
it says the obj must have all the keys. Wrong.
If i do one of
const mine: Partial<Record<Possibilities, string>>; const mine: {[key in Possibilities]?: string};
it allow me to set only some, however, types gets out as
string | undefined
. Even if "casting" objectas const
.Pick<>
orOmit<>
, for every single "instance" created, makes the desired result, but it's a pain in the ass, and kind of repeating myself (need to write"a", "b"...
on type and again on value).Also, at least here,
Omit<>
is not even auto-completing the possible values. Making it even harder and/or error prone when using most of possibilities, by needing to pick a lot or omit 'blindly'.
I got a feeling that the solution is somewhere close by using a generic that may extend the type... But couldn't figure it out.
--- EDIT ---
@tokland comment took me to an "almost there" solution
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
type Possibilities = "a" | "b" | "c"
let mine: AtLeastOne<Record<Possibilities, string>>;
This enforces the object to have a, b or c prop. Forbids it to have unknown props. And correctly outputs prop's type as not "possibly undefined"
But it breaks apart when multiple allowed props are set