I would like to correctly type the following function:
const noCI = itOrDescribe => (isCI ? itOrDescribe.skip : itOrDescribe)
Here's my first attempt:
const noCI = <T extends Mocha.SuiteFunction | Mocha.TestFunction>(itOrDescribe: T) => (isCI ? itOrDescribe.skip : itOrDescribe)
By 'correctly', I mean that the code should correctly infer that if describe
which is of type Mocha.SuiteFunction
gets passed in, the return type should be Mocha.SuiteFunction | Mocha.PendingSuiteFunction
, and if it
gets passed in, the return type should be Mocha.TestFunction | Mocha.PendingTestFunction
.
Instead, the type is always inferred as Mocha.PendingSuiteFunction | Mocha.PendingTestFunction
, regardless of which type gets passed in. Why?
To put my generics question more generically, I want a function that takes either a type A or a type B, and depending on whether A or B is passed, return a type derived from either A or B.
When you don't like the type Typescript infers, you can always just annotate it yourself.
And in this case that looks like: T | T['skip']
.
import Mocha, { it, describe } from 'mocha'
declare const isCI: boolean
const noCI = <
T extends Mocha.SuiteFunction | Mocha.TestFunction
>(itOrDescribe: T): T | T['skip'] => (
isCI ? itOrDescribe.skip : itOrDescribe
)
const noCiIt = noCI(it)
// Mocha.PendingSuiteFunction | Mocha.PendingTestFunction
const noCiDescribe = noCI(describe)
// Mocha.PendingSuiteFunction | Mocha.PendingTestFunction
noCiDescribe('test', () => {
noCiIt('test', () => {
//...
})
})