Skip to main content

Overview

The unknown decoder accepts anything and returns it unchanged. It provides no runtime validation but gives you a properly typed unknown value that you can refine later. This is useful when you don’t know or don’t care about the specific type of some data.

Basic Usage

import { unknown } from 'decoders';

const result = unknown.verify('hello');
// Type: unknown
// Result: 'hello'

const result2 = unknown.verify({ foo: 'bar' });
// Type: unknown
// Result: { foo: 'bar' }

const result3 = unknown.verify(null);
// Type: unknown
// Result: null

Type Signature

const unknown: Decoder<unknown>;

Parameters

None. unknown is a pre-built decoder instance, not a function.

Return Value

Returns a Decoder<unknown> that accepts any input and returns it with type unknown.

Examples

Accepting arbitrary metadata

import { object, string, number, unknown } from 'decoders';

const eventDecoder = object({
  type: string,
  timestamp: number,
  // Accept any metadata without validation
  metadata: unknown,
});

const event = eventDecoder.verify({
  type: 'user.login',
  timestamp: 1234567890,
  metadata: {
    ip: '192.168.1.1',
    userAgent: 'Mozilla/5.0...',
    customData: [1, 2, 3],
  },
});
// Type: { type: string; timestamp: number; metadata: unknown }

// You need to refine the type before using metadata
if (typeof event.metadata === 'object' && event.metadata !== null) {
  // Now you can safely access properties
}

Partial validation

import { object, string, unknown } from 'decoders';

const messageDecoder = object({
  id: string,
  // We know there's a body, but don't care about its structure
  body: unknown,
});

const message = messageDecoder.verify({
  id: 'msg-123',
  body: { text: 'Hello', format: 'plain' },
});
// Type: { id: string; body: unknown }

Passthrough fields

import { object, string, number, unknown } from 'decoders';

const configDecoder = object({
  apiKey: string,
  timeout: number,
  // Accept any additional options without validation
  options: unknown,
});

const config = configDecoder.verify({
  apiKey: 'secret',
  timeout: 5000,
  options: {
    retries: 3,
    backoff: 'exponential',
    customSetting: true,
  },
});
// The options are preserved but have type unknown

With type guards

import { unknown } from 'decoders';

function isStringArray(value: unknown): value is string[] {
  return Array.isArray(value) && value.every(item => typeof item === 'string');
}

const data = unknown.verify(['a', 'b', 'c']);
// Type: unknown

if (isStringArray(data)) {
  // Type: string[]
  data.forEach(item => console.log(item.toUpperCase()));
}

When to Use

Use unknown when:
  • You’re working with truly dynamic data where the structure is unpredictable
  • You want to defer validation to a later stage
  • You need to pass through data without modification
  • You’re building generic utilities that work with any type
  • You want to accept plugin configurations or extension points
Prefer specific decoders when possible. unknown provides no runtime safety, so you’re responsible for type-checking the data before using it.

Type Safety

The unknown type in TypeScript is safer than any because it requires you to refine the type before using it:
import { unknown } from 'decoders';

const data = unknown.verify({ message: 'Hello' });

// Error: Object is of type 'unknown'
data.message;

// Correct: refine the type first
if (typeof data === 'object' && data !== null && 'message' in data) {
  console.log((data as { message: unknown }).message);
}

// Or use a type guard
function hasMessage(value: unknown): value is { message: string } {
  return typeof value === 'object' && value !== null && 'message' in value;
}

if (hasMessage(data)) {
  console.log(data.message.toUpperCase());
}

Alias: anything

The anything decoder is an alias for unknown:
import { anything } from 'decoders';

const result = anything.verify('hello');
// Type: unknown
// Identical to: unknown.verify('hello')

Comparison with Other Decoders

DecoderValidationTypeUse Case
unknownNoneunknownAccept anything, refine later
stringMust be stringstringValidate strings
numberMust be numbernumberValidate numbers
constant(x)Must equal xLiteral typeValidate exact values
always(x)NoneType of xIgnore input, return x

Error Handling

The unknown decoder never fails validation:
import { unknown } from 'decoders';

// All of these succeed
unknown.verify('string');
unknown.verify(123);
unknown.verify(null);
unknown.verify(undefined);
unknown.verify({ complex: { nested: ['structure'] } });
unknown.verify(() => 'function');
  • always - Ignore input and return a specific value
  • constant - Validate exact literal values
  • lazy - Defer decoder evaluation for recursive types

See Also

Build docs developers (and LLMs) love