I'm creating a function which takes a boolean indicator object like:
const fruits = {
apple: false,
banana: false,
orange: false,
mango: false,
};
And an array like ['apple', 'orange']
. It should return object similar in structure of input object
with properties in array turned true
.
I've these typescript functions to achieve it
// Helper function to type Object.Keys
const objectKeysTyped = <Obj extends object>(obj: Obj) => {
return Object.keys(obj) as (keyof Obj)[];
};
// Main function
const arrayToBoolIndicator = <Obj extends Record<string, boolean>>(
boolFramework: Obj,
arrayOfIncluded: (keyof Obj)[]
) => {
return objectKeysTyped(boolFramework).reduce(
(acc, cur) => {
// TS Error next line: Type 'boolean' is not assignable to type 'Obj[keyof Obj]'.
acc[cur] = arrayOfIncluded.includes(cur);
return acc;
},
{ ...boolFramework }
);
};
Why am I getting the TS error while I'm assigning original type to object's property?
CodePudding user response:
The compiler cannot guarantee that boolean
is assignable to the properties of Obj
; all we know is the reverse. This is a concern because there exist true
and false
literal types which are more specific than boolean
. If you have a property of type true
then you can't safely assign a boolean
value to it because that value might be false
. Similarly if you have a property of type false
then you can't sagely assign a boolean
value to it because that value might be true
. Thus the compiler complains about assigning a boolean
value to acc[cur]
.
For example:
const x = { a: true, b: false } as const;
/* const x: { readonly a: true; readonly b: false; } */
const y = arrayToBoolIndicator(x, ["b"]);
// const y: { readonly a: true; readonly b: false; }
console.log(y); // {a: false, b: true}, uh oh
(y.a && "abc").toUpperCase(); // compiles fine, but