Skip to content

Optional values

Values flow between Tasks and Wires. Every value a Task reads is required by default. optional marks one as not required — when the source is missing, the Task still runs and the field is undefined.

optional works in both run.context and enabled.context.

import { compose, createTask, optional } from "@grlt-hub/app-compose"
const user = createTask({
name: "user",
run: {
fn: () => ({ name: "John" }),
},
})
const location = createTask({
name: "location",
run: { fn: () => "Antarctica" },
})
const greeting = createTask({
name: "greeting",
run: {
context: { user: optional(user.result) }, // 👈
fn: ({ user }) => {
console.log(`Hello, ${user?.name ?? "<unknown-user>"}`)
},
},
})
const recommendations = createTask({
name: "recommendations",
run: {
fn: () => console.log("recommendations loaded"),
},
enabled: {
context: [
optional(user.result), // 👈
optional(location.result), // 👈
],
fn: (ctx) => ctx.some((x) => x !== undefined),
},
})
// Try commenting a step:
// .step(user) → "<unknown-user>", recommendations run
// .step(location) → "Hello, John", recommendations run
// both → "<unknown-user>", recommendations skip
compose()
.step(user)
.step(greeting)
.step(location)
.step(recommendations)
.run()

optional works in createWire.from. The destination tag carries T | undefined.

import { compose, createTask, createWire, optional, tag } from "@grlt-hub/app-compose"
const userName = tag<string | undefined>("userName")
const user = createTask({
name: "user",
run: {
fn: () => ({ name: "John" }),
},
})
const greeting = createTask({
name: "greeting",
run: {
context: {
name: userName.value,
},
fn: ({ name }) => {
console.log(`Welcome back, ${name ?? "<unknown-user>"}`)
},
},
})
const userNameWire = createWire({
from: optional(user.result.name), // 👈
to: userName,
})
compose()
// 👇 comment — greeting → "<unknown-user>"
.step(user)
.step(userNameWire)
.step(greeting)
.run()

optional works in shape. The callback receives T | undefined.

import { compose, createTask, createWire, optional, shape, tag } from "@grlt-hub/app-compose"
const userName = tag<string>("userName")
const user = createTask({
name: "user",
run: { fn: () => ({ name: "John" }) },
})
const greeting = createTask({
name: "greeting",
run: {
context: {
name: userName.value,
},
fn: ({ name }) => console.log(`Welcome back, ${name}`),
},
})
const userNameShape = shape(
optional(user.result.name), // 👈
(name) => name ?? "<unknown-user>"
)
const userNameWire = createWire({
from: userNameShape,
to: userName,
})
compose()
// 👇 comment — greeting → "<unknown-user>"
.step(user)
.step(userNameWire)
.step(greeting)
.run()