Overview
The instanceOf() decoder validates that a value is an instance of a specific class using JavaScript’s instanceof operator. This is useful for validating built-in types like Date, Error, RegExp, or custom classes.
Basic Usage
import { instanceOf } from 'decoders';
const dateDecoder = instanceOf(Date);
const date = dateDecoder.verify(new Date());
// Type: Date
// Result: Date instance
dateDecoder.verify('2024-01-01'); // Error: Must be Date instance
dateDecoder.verify(1704067200000); // Error: Must be Date instance
Type Signature
function instanceOf<K extends Klass<any>>(klass: K): Decoder<Instance<K>>;
interface Klass<T> extends Function {
new (...args: readonly any[]): T;
}
type Instance<K> = K extends Klass<infer T> ? T : never;
Parameters
klass
Class constructor
required
The class constructor to check against. Must be a class that can be used with the instanceof operator.
Return Value
Returns a Decoder<T> where T is the instance type of the provided class.
Examples
Date validation
import { instanceOf, object, string } from 'decoders';
const eventDecoder = object({
name: string,
createdAt: instanceOf(Date),
});
const event = eventDecoder.verify({
name: 'Conference',
createdAt: new Date('2024-03-15'),
});
// Type: { name: string; createdAt: Date }
eventDecoder.verify({
name: 'Conference',
createdAt: '2024-03-15', // Error: Must be Date instance
});
Error instances
import { instanceOf } from 'decoders';
const errorDecoder = instanceOf(Error);
const error = errorDecoder.verify(new Error('Something went wrong'));
// Type: Error
const typeError = errorDecoder.verify(new TypeError('Wrong type'));
// Type: Error (also works with subclasses)
errorDecoder.verify({ message: 'Not an error' }); // Error: Must be Error instance
RegExp validation
import { instanceOf } from 'decoders';
const regexDecoder = instanceOf(RegExp);
const pattern = regexDecoder.verify(/[a-z]+/i);
// Type: RegExp
const pattern2 = regexDecoder.verify(new RegExp('[0-9]+'));
// Type: RegExp
regexDecoder.verify('[a-z]+'); // Error: Must be RegExp instance
Custom classes
import { instanceOf, object, string, number } from 'decoders';
class User {
constructor(
public id: number,
public name: string
) {}
greet() {
return `Hello, ${this.name}!`;
}
}
const userDecoder = instanceOf(User);
const user = userDecoder.verify(new User(1, 'Alice'));
// Type: User
user.greet(); // OK: 'Hello, Alice!'
userDecoder.verify({ id: 1, name: 'Alice' }); // Error: Must be User instance
Map and Set validation
import { instanceOf } from 'decoders';
const mapDecoder = instanceOf(Map);
const setDecoder = instanceOf(Set);
const map = mapDecoder.verify(new Map([['a', 1], ['b', 2]]));
// Type: Map<any, any>
const set = setDecoder.verify(new Set([1, 2, 3]));
// Type: Set<any>
mapDecoder.verify({ a: 1, b: 2 }); // Error: Must be Map instance
setDecoder.verify([1, 2, 3]); // Error: Must be Set instance
With inheritance
import { instanceOf } from 'decoders';
class Animal {
constructor(public name: string) {}
}
class Dog extends Animal {
bark() {
return 'Woof!';
}
}
const animalDecoder = instanceOf(Animal);
// Dog instances are also Animal instances
const dog = animalDecoder.verify(new Dog('Rex'));
// Type: Animal
const animal = animalDecoder.verify(new Animal('Generic'));
// Type: Animal
animalDecoder.verify({ name: 'Not an animal' }); // Error
Array-like objects
import { instanceOf } from 'decoders';
const arrayDecoder = instanceOf(Array);
const arr = arrayDecoder.verify([1, 2, 3]);
// Type: any[]
const arr2 = arrayDecoder.verify(new Array(5));
// Type: any[]
arrayDecoder.verify({ 0: 'a', 1: 'b', length: 2 }); // Error: Not an Array instance
Error Messages
The instanceOf() decoder provides clear error messages using the class name:
import { instanceOf } from 'decoders';
const dateDecoder = instanceOf(Date);
try {
dateDecoder.verify('2024-01-01');
} catch (error) {
console.error(error.message);
// Must be Date instance
}
class CustomClass {}
const customDecoder = instanceOf(CustomClass);
try {
customDecoder.verify({});
} catch (error) {
console.error(error.message);
// Must be CustomClass instance
}
Type Inference
TypeScript correctly infers the instance type:
import { instanceOf } from 'decoders';
class MyClass {
method() {}
}
const decoder = instanceOf(MyClass);
type InferredType = ReturnType<typeof decoder.verify>;
// Type: MyClass
const instance = decoder.verify(new MyClass());
instance.method(); // OK: TypeScript knows about the method
Caveats
The instanceof operator has limitations:
- It doesn’t work across different JavaScript execution contexts (e.g., iframes)
- It only checks the prototype chain, not the actual structure
- Primitives are not instances:
"hello" instanceof String is false
// These are NOT instances
instanceOf(String).verify('hello'); // Error
instanceOf(Number).verify(42); // Error
instanceOf(Boolean).verify(true); // Error
// These ARE instances
instanceOf(String).verify(new String('hello')); // OK (but unusual)
instanceOf(Number).verify(new Number(42)); // OK (but unusual)
Use Cases
- Validating Date objects from JSON parsing with custom revivers
- Checking Error instances in error handling code
- Validating custom class instances from serialized data
- Type guarding for polymorphic class hierarchies
- API boundaries where classes are passed between modules
Comparison with Other Validators
| Check | Code | Accepts |
|---|
| Instance check | instanceOf(Date) | new Date() |
| Type check | date decoder | ISO date strings (converted) |
| Duck typing | object({ getTime: ... }) | Any object with matching shape |
date - Parses and validates date strings
object - Validates object structure
unknown - Accepts any value
See Also