I have a function createUnion
that takes an array of callbacks with different return types and returns one of the results. I want it to return a union of the return types. It works perfectly when combining types with null
or undefined
, but not other types. They are not even done in order precedence. How can I correctly infer the union type from all the callbacks?
<code>function createUnion <Creation> (creators: Array<() => Creation>): Creation {
const index = Math.floor(Math.random() * creators.length)
const creator = creators[index]
const creation = creator()
return creation
}
function createNumber (): number {
return 42
}
function createString (): string {
return 'Hello'
}
function createNull (): null {
return null
}
function createUndefined (): undefined {
return undefined
}
function createBoolean (): boolean {
return true
}
// Correctly typed as string | null
export const stringOrNull = createUnion([
createString,
createNull
])
// Correctly typed as number | undefined
export const numberOrUndefined = createUnion([
createNumber,
createUndefined
])
// Incorrectly typed as string
export const stringOrNumber = createUnion([
createString,
createNumber // Type '() => number' is not assignable to type '() => string'.
// Type 'number' is not assignable to type 'string'.ts(2322)
])
// Incorrectly typed as string
export const numberOrString = createUnion([
createNumber, // Type '() => number' is not assignable to type '() => string '.
createString
])
// Incorrectly typed as number
export const numberOrBoolean = createUnion([
createBoolean, // Type '() => boolean' is not assignable to type '() => number'.
// Type 'boolean' is not assignable to type 'number'.ts(2322)
createNumber
])
</code>
<code>function createUnion <Creation> (creators: Array<() => Creation>): Creation {
const index = Math.floor(Math.random() * creators.length)
const creator = creators[index]
const creation = creator()
return creation
}
function createNumber (): number {
return 42
}
function createString (): string {
return 'Hello'
}
function createNull (): null {
return null
}
function createUndefined (): undefined {
return undefined
}
function createBoolean (): boolean {
return true
}
// Correctly typed as string | null
export const stringOrNull = createUnion([
createString,
createNull
])
// Correctly typed as number | undefined
export const numberOrUndefined = createUnion([
createNumber,
createUndefined
])
// Incorrectly typed as string
export const stringOrNumber = createUnion([
createString,
createNumber // Type '() => number' is not assignable to type '() => string'.
// Type 'number' is not assignable to type 'string'.ts(2322)
])
// Incorrectly typed as string
export const numberOrString = createUnion([
createNumber, // Type '() => number' is not assignable to type '() => string '.
createString
])
// Incorrectly typed as number
export const numberOrBoolean = createUnion([
createBoolean, // Type '() => boolean' is not assignable to type '() => number'.
// Type 'boolean' is not assignable to type 'number'.ts(2322)
createNumber
])
</code>
function createUnion <Creation> (creators: Array<() => Creation>): Creation {
const index = Math.floor(Math.random() * creators.length)
const creator = creators[index]
const creation = creator()
return creation
}
function createNumber (): number {
return 42
}
function createString (): string {
return 'Hello'
}
function createNull (): null {
return null
}
function createUndefined (): undefined {
return undefined
}
function createBoolean (): boolean {
return true
}
// Correctly typed as string | null
export const stringOrNull = createUnion([
createString,
createNull
])
// Correctly typed as number | undefined
export const numberOrUndefined = createUnion([
createNumber,
createUndefined
])
// Incorrectly typed as string
export const stringOrNumber = createUnion([
createString,
createNumber // Type '() => number' is not assignable to type '() => string'.
// Type 'number' is not assignable to type 'string'.ts(2322)
])
// Incorrectly typed as string
export const numberOrString = createUnion([
createNumber, // Type '() => number' is not assignable to type '() => string '.
createString
])
// Incorrectly typed as number
export const numberOrBoolean = createUnion([
createBoolean, // Type '() => boolean' is not assignable to type '() => number'.
// Type 'boolean' is not assignable to type 'number'.ts(2322)
createNumber
])