I came across some unexpected behavior when trying to expand mapped type I created from an union of object types, when trying to use this type within conditional type: Playground
export type CompErrors = {
type: "compilation_errors"
val: number
}
export type TestErrors = {
type: "test_errors"
}
export type TestInfo = {
type: 'test_info'
}
export type Entities = CompErrors | TestErrors | TestInfo
I create a Type that transform union of object types into and object type where keys are matching type property’s value.
This works as expected, and when used as function parameter I am forced to fill all the keys.
type EntityMap<Type>
= {
[T in Extract<Type, { type: string }> as T["type"]]: ((par: T) => any) | string | boolean | object
}
type Params = EntityMap<Entities>
const entityMapFn = (params: Params) => {}
// missing test_info prop makes error only here
entityMapFn({
compilation_errors: "",
test_errors: "",
})
Next I want to expand this type to change the result type based on condition, I add a boolean check and since this branch is not hit in ParamAlternative type I expect that the resulting type will be exactly the same as in case of Params type above.
This is not the case though, and while I still have an auto-completion with correct types for resulting object, now I don’t need to provide all the properties in the object, since the resulting object type is different than in previous case.
type EntityMapAlternative<Type>
= Type extends boolean ? string : {
[T in Extract<Type, { type: string }> as T["type"]]: ((par: T) => any) | string | boolean | object
}
type ParamsAlternative = EntityMapAlternative<Entities>
const entityMapAlternativeFn = (params: ParamsAlternative) => {}
//no error for missing prop
entityMapAlternativeFn({
compilation_errors: "",
test_errors: (te) => {te.type},
})
I was wondering whether the condition doesn’t somehow affect the mapped type below it, so I tried to make a type where conditional type is processed outside of next attempt.
This however yields the same result:
type EntityMapExtracted<Type>
= Type extends boolean ? string : EntityMap<Type>
type ParamsExtracted = EntityMapExtracted<Entities>
const entityMapExtractedFn = (params: ParamsExtracted) => {}
//no error for missing prop
entityMapExtractedFn({
compilation_errors: "",
test_errors: (te) => {te.type},
})
type ParamsExtractedWithBool = EntityMapExtracted<boolean>
const withBool = (params: ParamsExtractedWithBool) => {}
// just check that this accepts only string nothing else
withBool("string accepted")
What exactly does cause this behavior, that changes the result type even though a branch with boolean condition is not hit?
How can I make this work as intended?