# optionalAsync

> This document is the Markdown version of [valibot.dev/api/optionalAsync/](https://valibot.dev/api/optionalAsync/). For the complete documentation index, see [llms.txt](https://valibot.dev/llms.txt).

Creates an optional schema.

```ts
const Schema = v.optionalAsync<TWrapped, TDefault>(wrapped, default_);
```

## Generics

- `TWrapped` `extends BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>`
- `TDefault` `extends DefaultAsync<TWrapped, undefined>`

## Parameters

- `wrapped` `TWrapped`
- `default_` `TDefault`

### Explanation

With `optionalAsync` the validation of your schema will pass `undefined` inputs, and if you specify a `default_` input value, the schema will use it if the input is `undefined`. For this reason, the output type may differ from the input type of the schema.

> **Important**: When used in object schemas, if a key is missing and no `default_` value is provided, the schema's pipe (including transformations) will not be executed. To ensure pipes run for missing keys, provide a `default_` value.

> Note that `optionalAsync` does not accept `null` as an input. If you want to accept `null` inputs, use [`nullableAsync`](/api/nullableAsync.md), and if you want to accept `null` and `undefined` inputs, use [`nullishAsync`](/api/nullishAsync.md) instead. Also, if you want to set a default output value for any invalid input, you should use [`fallbackAsync`](/api/fallbackAsync.md) instead.

## Returns

- `Schema` `OptionalSchemaAsync<TWrapped, TDefault>`

## Examples

The following examples show how `optionalAsync` can be used.

### Optional username schema

Schema that accepts a unique username or `undefined`.

> By using a function as the `default_` parameter, the schema will return a unique username from the function call each time the input is `undefined`.

```ts
import { getUniqueUsername, isUsernameUnique } from '~/api';

const OptionalUsernameSchema = v.optionalAsync(
  v.pipeAsync(
    v.string(),
    v.nonEmpty(),
    v.checkAsync(isUsernameUnique, 'The username is not unique.')
  ),
  getUniqueUsername
);
```

### New user schema

Schema to validate new user details.

```ts
import { isEmailUnique, isUsernameUnique } from '~/api';

const NewUserSchema = v.objectAsync({
  email: v.pipeAsync(
    v.string(),
    v.email(),
    v.checkAsync(isEmailUnique, 'The email is not unique.')
  ),
  username: v.optionalAsync(
    v.pipeAsync(
      v.string(),
      v.nonEmpty(),
      v.checkAsync(isUsernameUnique, 'The username is not unique.')
    )
  ),
  password: v.pipe(v.string(), v.minLength(8)),
});

/*
  The input and output types of the schema:
    {
      email: string;
      password: string;
      username?: string | undefined;
    }
*/
```

### Unwrap optional schema

Use [`unwrap`](/api/unwrap.md) to undo the effect of `optionalAsync`.

```ts
import { isUsernameUnique } from '~/api';

const UsernameSchema = v.unwrap(
  // Assume this schema is from a different file and is reused here
  v.optionalAsync(
    v.pipeAsync(
      v.string(),
      v.nonEmpty(),
      v.checkAsync(isUsernameUnique, 'The username is not unique.')
    )
  )
);
```

### Optional async with pipes

When using `optionalAsync` in a [`pipeAsync`](/api/pipeAsync.md), the pipe actions only execute if a `default_` value is provided or the key is present. This applies to all pipe actions including [`transformAsync`](/api/transformAsync.md), [`checkAsync`](/api/checkAsync.md), and others.

```ts
const SchemaWithoutDefault = v.objectAsync({
  isActive: v.pipeAsync(
    v.optionalAsync(v.string()),
    v.transformAsync(async (value) => value === 'true') // Does not run for missing keys
  ),
}); // Output type: { isActive?: boolean }

const SchemaWithDefault = v.objectAsync({
  isActive: v.pipeAsync(
    v.optionalAsync(v.string(), 'false'), // Default value provided
    v.transformAsync(async (value) => value === 'true') // Runs for missing keys too
  ),
}); // Output type: { isActive: boolean }
```

## Related

The following APIs can be combined with `optionalAsync`.

### Schemas

[`any`](/api/any.md), [`array`](/api/array.md), [`bigint`](/api/bigint.md), [`blob`](/api/blob.md), [`boolean`](/api/boolean.md), [`custom`](/api/custom.md), [`date`](/api/date.md), [`enum`](/api/enum.md), [`exactOptional`](/api/exactOptional.md), [`file`](/api/file.md), [`function`](/api/function.md), [`instance`](/api/instance.md), [`intersect`](/api/intersect.md), [`lazy`](/api/lazy.md), [`literal`](/api/literal.md), [`looseObject`](/api/looseObject.md), [`looseTuple`](/api/looseTuple.md), [`map`](/api/map.md), [`nan`](/api/nan.md), [`never`](/api/never.md), [`nonNullable`](/api/nonNullable.md), [`nonNullish`](/api/nonNullish.md), [`nonOptional`](/api/nonOptional.md), [`null`](/api/null.md), [`nullable`](/api/nullable.md), [`nullish`](/api/nullish.md), [`number`](/api/number.md), [`object`](/api/object.md), [`objectWithRest`](/api/objectWithRest.md), [`optional`](/api/optional.md), [`picklist`](/api/picklist.md), [`promise`](/api/promise.md), [`record`](/api/record.md), [`set`](/api/set.md), [`strictObject`](/api/strictObject.md), [`strictTuple`](/api/strictTuple.md), [`string`](/api/string.md), [`symbol`](/api/symbol.md), [`tuple`](/api/tuple.md), [`tupleWithRest`](/api/tupleWithRest.md), [`undefined`](/api/undefined.md), [`undefinedable`](/api/undefinedable.md), [`union`](/api/union.md), [`unknown`](/api/unknown.md), [`variant`](/api/variant.md), [`void`](/api/void.md)

### Methods

[`config`](/api/config.md), [`getDefault`](/api/getDefault.md), [`getFallback`](/api/getFallback.md), [`unwrap`](/api/unwrap.md)

### Actions

[`brand`](/api/brand.md), [`check`](/api/check.md), [`description`](/api/description.md), [`flavor`](/api/flavor.md), [`guard`](/api/guard.md), [`metadata`](/api/metadata.md), [`partialCheck`](/api/partialCheck.md), [`rawCheck`](/api/rawCheck.md), [`rawTransform`](/api/rawTransform.md), [`readonly`](/api/readonly.md), [`title`](/api/title.md), [`transform`](/api/transform.md)

### Utils

[`entriesFromList`](/api/entriesFromList.md), [`isOfKind`](/api/isOfKind.md), [`isOfType`](/api/isOfType.md)

### Async

[`arrayAsync`](/api/arrayAsync.md), [`awaitAsync`](/api/awaitAsync.md), [`checkAsync`](/api/checkAsync.md), [`customAsync`](/api/customAsync.md), [`exactOptionalAsync`](/api/exactOptionalAsync.md), [`fallbackAsync`](/api/fallbackAsync.md), [`getDefaultsAsync`](/api/getDefaultsAsync.md), [`getFallbacksAsync`](/api/getFallbacksAsync.md), [`intersectAsync`](/api/intersectAsync.md), [`lazyAsync`](/api/lazyAsync.md), [`looseObjectAsync`](/api/looseObjectAsync.md), [`looseTupleAsync`](/api/looseTupleAsync.md), [`mapAsync`](/api/mapAsync.md), [`nonNullableAsync`](/api/nonNullableAsync.md), [`nonNullishAsync`](/api/nonNullishAsync.md), [`nonOptionalAsync`](/api/nonOptionalAsync.md), [`nullableAsync`](/api/nullableAsync.md), [`nullishAsync`](/api/nullishAsync.md), [`objectAsync`](/api/objectAsync.md), [`objectWithRestAsync`](/api/objectWithRestAsync.md), [`parseAsync`](/api/parseAsync.md), [`parserAsync`](/api/parserAsync.md), [`partialCheckAsync`](/api/partialCheckAsync.md), [`pipeAsync`](/api/pipeAsync.md), [`rawCheckAsync`](/api/rawCheckAsync.md), [`rawTransformAsync`](/api/rawTransformAsync.md), [`recordAsync`](/api/recordAsync.md), [`safeParseAsync`](/api/safeParseAsync.md), [`safeParserAsync`](/api/safeParserAsync.md), [`setAsync`](/api/setAsync.md), [`strictObjectAsync`](/api/strictObjectAsync.md), [`strictTupleAsync`](/api/strictTupleAsync.md), [`transformAsync`](/api/transformAsync.md), [`tupleAsync`](/api/tupleAsync.md), [`tupleWithRestAsync`](/api/tupleWithRestAsync.md), [`undefinedableAsync`](/api/undefinedableAsync.md), [`unionAsync`](/api/unionAsync.md), [`variantAsync`](/api/variantAsync.md)
