type Formula =
| {
fn: (a: number) => number;
arg: number;
}
| {
fn: (a: () => number) => number;
arg: () => number;
};
In this example, how can I type Formula so that fn always accepts arg as a parameter? I still need something like the Formula type to represent both kinds of formulas in case I want to mix them in a list or create a function that can return either type.
formula1.fn(formula1.arg) // should always work.
In other words:
- If
argis anumber,fnshould be a(number) => number - If
argis a() => number,fnshould be a(() => number) => number - There exists one type which covers both types of formula.
// Just applies formula.fn to formula.arg
const calc = (
formula: Formula
) => formula.fn(formula.arg); // formula.arg fails to type check
/*
Argument of type 'number | (() => number)' is not assignable to parameter of type 'number & (() => number)'.
Type 'number' is not assignable to type 'number & (() => number)'.
Type 'number' is not assignable to type '() => number'.ts(2345)
*/
// Should succeed (fn takes a number and arg is a number)
const num1 = calc({
fn: (a) => a + 1,
arg: 3
})
// Should succeed (fn takes a () => number and arg is a () => number)
const num2 = calc({
fn: (a) => a() + 1,
arg: () => 3
})
// Should fail because arg is a number and fn expects a () => number parameter
const num3 = calc({
fn: (a) => a() + 1,
arg: 4
})
// Should fail because arg is a () => number and fn expects a number parameter
const num4 = calc({
fn: (a) => a + 1,
arg: () => 4
})
// It should be possible to build an array
// containing types of formulas.
const formulas: Formula = [
// plain number formula
{
fn: a => a + 3,
arg: 4
},
// () => number formula
{
fn: a => a() * 2,
arg: () => 11
}
]
const answers = formulas.map(calc)
Thanks!