bitrevolution
bitrevolution

Reputation: 467

Typescript: Optional Parameter in function, depending on Union Type has property

I have a union type:

type Msg = { type: 'banana', value: number[] } | { type: 'apple' };

now i would like to create a function that creates such a Fruit type, with two arguments and takes a generic for the Msg:

const createMsg = <M extends { type: string }>(type: M["type"], value?: M["value"]) => ({ type, value });

The value argument of the function should be linked to the type of value of the union type, and if it's not defined, the param should be optional. I would like to be able to call it in two ways:

createMsg('banana', [1, 2, 3]);
createMsg('apple');

All my current solutions so far forced me to provide a second argument undefined for the 'apple' union-type.

Upvotes: 3

Views: 1484

Answers (3)

tokland
tokland

Reputation: 67860

Type-safe functions with variable arity: playground

type Msg = { type: "apple" } | { type: "banana"; value: number[] };

type MsgArgs = ["apple"] | ["banana", number[]];

function createMsg(...args: MsgArgs): Msg {
    if (args[0] === "banana") {
        return { type: "banana", value: args[1] };
    } else {
        return { type: "apple" };
    }
}

const banana = createMsg("banana", [1, 2, 3]);
const apple_ = createMsg("apple");

Upvotes: 0

tenshi
tenshi

Reputation: 26324

Another method would be to use overloads (although this can get finicky with many more constituents):

type Type = { type: "foo"; value: number[] } | { type: "bar" };

function createMessage(type: "foo", value: number[]): Type;
function createMessage(type: "bar"): Type;
function createMessage(type: "foo" | "bar", value?: number[]) {
    if (value) return { type, value };
    
    return { type };
}

Playground

Upvotes: 0

Nullndr
Nullndr

Reputation: 1827

You can't have conditional parameters, the most simple way to do this is to pass a Msg to createMsg:

const createMsg = (msg: Msg): Msg => (msg)

const a = createMsg({ type: "apple" })
const b = createMsg({ type: "banana", value: [1,2,3] })

Upvotes: 3

Related Questions