A lightweight TypeScript/JavaScript library for implementing the Chain of Responsibility pattern with class-based resolvers.
- Simple and intuitive API for handling different types of requests
- Type-safe implementation with TypeScript support
- Flexible resolver registration (constructor, setUpdaters, addUpdater)
- Support for multiple resolvers with different handling logic
- Clear error handling for unsupported types
- Generic type support for better type safety
npm install class-resolver
# or
yarn add class-resolver
const Resolver = require('class-resolver')
class ExampleClass {
supports(type) {
return type === 'hoge'
}
handle() {
return 'hoge'
}
}
class ExampleClass2 {
supports(type) {
return type === 'fuga'
}
handle() {
return 'fuga'
}
}
const resolver = new Resolver(new ExampleClass(), new ExampleClass2())
const c = resolver.resolve('hoge')
console.log(c.handle()) // Output: hoge
const c2 = resolver.resolve('fuga')
console.log(c2.handle()) // Output: fuga
try {
resolver.resolve('xxx') // This will throw an error
} catch (e) {
console.log(e) // Error: Unsupported type: xxx
}
import Resolver from 'class-resolver';
import { ResolveTarget } from 'class-resolver';
// Using generics for better type safety
class MessageFormatter implements ResolveTarget<[string, number], string> {
supports(type: string): boolean {
return type === 'greeting'
}
handle(name: string, count: number): string {
return `Hello ${name}, this is message #${count}!`
}
}
class ErrorFormatter implements ResolveTarget<[string, number], string> {
supports(type: string): boolean {
return type === 'error'
}
handle(message: string, code: number): string {
return `Error ${code}: ${message}`
}
}
// Specify the generic type for better type safety
const resolver = new Resolver<ResolveTarget<[string, number], string>>(
new MessageFormatter(),
new ErrorFormatter()
)
// Using the greeting formatter
const greeting = resolver.resolve('greeting')
console.log(greeting.handle('John', 1)) // Output: Hello John, this is message #1!
// Using the error formatter
const error = resolver.resolve('error')
console.log(error.handle('Not Found', 404)) // Output: Error 404: Not Found
// Specify the generic type for better type safety
const resolver = new Resolver<ResolveTarget<[string, number], string>>()
// Add resolvers after initialization
resolver.setUpdaters(new MessageFormatter(), new ErrorFormatter())
// Or add them one by one
resolver.addUpdater(new MessageFormatter())
resolver.addUpdater(new ErrorFormatter())
From version 2.0.0, class-resolver supports generic types for better type safety:
// Define the interface with generics
interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> {
supports(type: string): boolean;
handle(...args: TArgs): TReturn;
}
// Define a class that implements the interface with specific types
class StringFormatter implements ResolveTarget<[string], string> {
supports(type: string): boolean {
return type === 'string-format';
}
handle(input: string): string {
return input.toUpperCase();
}
}
// Create a resolver with the specific type
const resolver = new Resolver<ResolveTarget<[string], string>>(new StringFormatter());
const formatter = resolver.resolve('string-format');
const result = formatter.handle('hello'); // result is typed as string
- Command Pattern Implementation: Handle different types of commands with specific handlers
- Format Conversion: Convert data between different formats based on type
- Request Processing: Process different types of requests with dedicated handlers
- Plugin System: Implement a plugin system where different plugins handle specific types of operations
- Message Formatting: Format different types of messages with specific formatters
The resolver will throw errors in the following cases:
- When no resolvers are registered:
"Unasigned resolve target."
- When trying to resolve an unsupported type:
"Unsupported type: xxx"
Version 2.0.0 introduces generic type support for better type safety. This change is backward compatible for JavaScript users, but TypeScript users may need to update their code.
-
The
ResolveTarget
interface now supports generics:// Before (1.x) interface ResolveTarget { supports(type: string): boolean; handle(...args: any[]): any; } // After (2.0.0) interface ResolveTarget<TArgs extends any[] = any[], TReturn = any> { supports(type: string): boolean; handle(...args: TArgs): TReturn; }
-
The
Resolver
class now supports generics:// Before (1.x) class Resolver { // ... } // After (2.0.0) class Resolver<TBase extends ResolveTarget = ResolveTarget> { // ... }
-
If you're using TypeScript with default
any
types, your code should continue to work without changes. -
To take advantage of the improved type safety, update your class implementations:
// Before (1.x) class MyHandler implements ResolveTarget { supports(type: string): boolean { return type === 'my-type'; } handle(name: string): string { return `Hello ${name}`; } } // After (2.0.0) class MyHandler implements ResolveTarget<[string], string> { supports(type: string): boolean { return type === 'my-type'; } handle(name: string): string { return `Hello ${name}`; } }
-
When creating a new Resolver, specify the generic type:
// Before (1.x) const resolver = new Resolver(new MyHandler()); // After (2.0.0) const resolver = new Resolver<ResolveTarget<[string], string>>(new MyHandler());
-
If you have mixed handler types, you can use a union type or keep using the default
any
type:// Using union type type MyHandlers = ResolveTarget<[string], string> | ResolveTarget<[number], boolean>; const resolver = new Resolver<MyHandlers>(new StringHandler(), new NumberHandler()); // Or keep using the default any type const resolver = new Resolver(new StringHandler(), new NumberHandler());
$ npm install
$ git checkout -b YOUR_TOPIC_BRANCH
$ npm test
$ npm run build
$ git add ./
$ git commit -m "YOUR UPDATE DESCRIPTION"
$ git push YOUR_ORIGIN YOUR_TOPIC_BRANCH
MIT