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!