The error message is because the btnWrap
type boolean
doesn't match the string index type string
. The type {[key: string]: string, btnWrap: boolean}}
is trying to say that every property has a string value and that btnWrap
has a boolean value. They can't both be true, so the compiler warns you.
There isn't a single concrete type MyObj
that represents the constraint as you described it. But you can create a generic type which takes the union of key literals K
and produces a type MyObj<K>
:
type MyObj<K extends keyof any> =
{ [P in K]: string | (Record<P, string> & { btnWrap: boolean }) };
The type MyObj<K>
is a mapped type where each property with key P
either has value type string
, or the intersection of {btnWrap: boolean}
with Record<P, string>
. The latter type is itself a mapped type (defined in the standard library) with keys P
and properties string
. So each property of MyObject<K>
must either look like someKey: string
or someKey: {btnWrap: boolean, someKey: string}
.
Again, to describe the type of myObj
, instead of something simple like let myObj: MyObj = ...
, you have to do something like let myObj: MyObj<"key1"|"key2"|"key3"> = ...
where you specify the generic parameters. To prevent you from having to do this yourself, you can use a generic helper function to help infer the type of K
given an object, like this:
const asMyObj = <T extends MyObj<keyof T>>(myObj: T) => myObj;
Now let's try it:
let myObj1 = asMyObj({ key1: 'val1', key2: 'val2', key3: 'val3' });
let myObj2 = asMyObj({ key1: 'val1', key2: { key2: 'val2', btnWrap: true }, key3: 'val3' });
Those work just fine. Now let's see what goes wrong if you violate your constraint:
let badMyObj1 = asMyObj({ key1: 1 });
// error, number is bad
let badMyObj2 = asMyObj({ key1: "val1", key2: { key2: "val2" } });
// error, missing btnWrap
let badMyObj3 = asMyObj({ key1: "val1", key2: { btnWrap: true } });
// error, missing key2 inside value
let badMyObj4 = asMyObj({ key1: "val1", key2: { key3: "val3", btnWrap: true } });
// error, key3 not expected inside value
Those errors are probably what you want to see, right?
Okay, hope that helps. Here's a Playground link to the above code. Good luck!