cfg() - A Flexible Configuration Value Handler in TypeScript
In Payload CMS, everything revolves around your configuration setup. I've been working on several Payload plugins and have found myself in need of a utility function that helps me retrieve configuration values while falling back to a provided default value. Specifically, I'm checking for the presence of new custom properties on my Payload CollectionConfig
.
In this article, I'll outline a versatile TypeScript utility function called cfg()
that simplifies the process of retrieving configuration values while providing type safety and flexible fallback options.
Introduction
The cfg()
utility function is designed to safely extract configuration values from objects while handling undefined cases and providing default values. What makes this function particularly useful is its ability to handle boolean conversions and its type-safe implementation using TypeScript's powerful type system.
Breaking Down the Function
Let's examine the key components of this utility:
Type Safety with Generics
export function cfg<T>(
obj: T | undefined | true,
prop: keyof T,
defaultValue: unknown = true)
The function uses TypeScript generics (<T>
) to ensure type safety. The first parameter obj
can be of type T
, undefined
, or true
, making it extremely flexible. The prop
parameter must be a valid key of type T
, preventing accidental access to non-existent properties.
Logical Flow
The function follows a clear decision tree:
- First, it checks if the input object is explicitly
true
:
if (obj === true) {
return true;
}
- Then, it attempts to retrieve the specified property using optional chaining:
const value = obj?.[prop];
- The value is evaluated based on its type:
- Boolean values are returned directly
- Undefined values trigger the default value
- Other values are converted to boolean
Real-World Applications
This utility is particularly useful in scenarios such as:
Feature Flags
interface FeatureFlags {
darkMode: boolean;
betaFeatures: boolean;
}
const flags = {
darkMode: true,
betaFeatures: undefined
};
const isDarkMode = cfg(flags, 'darkMode'); // true
const hasBetaFeatures = cfg(flags, 'betaFeatures'); // true (default)
Configuration Management
interface AppConfig {
isDebugMode: boolean;
enableAnalytics: number; // 0 or 1
}
const config = {
isDebugMode: true,
enableAnalytics: 1
};
const analyticsEnabled = cfg(config, 'enableAnalytics'); // true
TypeScript Benefits
The implementation leverages several TypeScript features that make the utility more robust:
- Generic Types: The
<T>
parameter allows the function to work with any object type while maintaining type safety. - Keyof Operator: Using
keyof T
ensures that only valid property names can be passed. - Union Types: The
T | undefined | true
type allows for flexible input handling. - Optional Chaining: The
?.
operator safely handles potential undefined values.
Considerations and Limitations
While the utility is powerful, there are some things to keep in mind:
- The function always returns a boolean value, so it's not suitable for retrieving non-boolean configuration values.
- The default value parameter is typed as
unknown
, which might be too permissive in some cases. - The automatic boolean conversion might not always be desirable for non-boolean input values.
Conclusion
The cfg()
utility function demonstrates how TypeScript's type system can be leveraged to create safe and flexible utilities for handling configuration values. Its ability to handle undefined cases, provide default values, and ensure type safety makes it a valuable tool for managing feature flags and configuration settings in TypeScript applications.
Whether you're building a complex application with multiple feature flags or simply need a reliable way to handle boolean configuration values, this utility provides a robust solution while maintaining code quality through strong typing.
Consider incorporating this utility into your TypeScript projects when you need a reliable way to handle configuration values with built-in type safety and flexible fallback options.