TypeScript接口优化:让options.sortBy类型依赖于type属性
Great question! Let's fix this type dependency issue and make your sort configuration more type-safe while cleaning up the iteratee logic.
Step 1: Refactor SortConfig for Type-Dependent Options
The core problem with your original interface is that it doesn't enforce the link between type and options.sortBy. To fix this, we'll use union types instead of a single interface—this lets us define strict rules for each SortValueType:
export enum SortValueType { String = 'string', Number = 'number', Date = 'date', } // Assuming you have this defined already; adjust if needed export enum SortDirection { Asc = 'asc', Desc = 'desc', } // Base config with shared properties type BaseSortConfig<T extends SortValueType> = { key: string; direction: SortDirection; type: T; }; // String type: no allowed sortBy in options type StringSortConfig = BaseSortConfig<SortValueType.String> & { options?: Omit<{ sortBy?: never }, 'sortBy'>; // Explicitly block sortBy }; // Number type: same as string—no sortBy allowed type NumberSortConfig = BaseSortConfig<SortValueType.Number> & { options?: Omit<{ sortBy?: never }, 'sortBy'>; }; // Date type: only here we allow sortBy with specific values type DateSortConfig = BaseSortConfig<SortValueType.Date> & { options?: { sortBy?: 'year' | 'day'; }; }; // Final union type—TypeScript will enforce the rules automatically export type SortConfig = StringSortConfig | NumberSortConfig | DateSortConfig;
Now TypeScript will throw an error if you try to set sortBy for anything other than Date type—exactly what you need!
Step 2: Optimize getIteratee with Type Guards
With the refactored SortConfig, we can use type guards to let TypeScript infer the exact config type in each branch, eliminating the need for manual as assertions. Here's the cleaned-up function:
import _ from 'lodash'; // Type guard to check if config is for Date sorting function isDateSortConfig(config: SortConfig): config is DateSortConfig { return config.type === SortValueType.Date; } // Type guard to check if config is for String sorting function isStringSortConfig(config: SortConfig): config is StringSortConfig { return config.type === SortValueType.String; } private getIteratee(config: SortConfig) { if (isStringSortConfig(config)) { return (item: Record<string, unknown>) => _.lowerCase(item[config.key] as string); } if (isDateSortConfig(config)) { const sortBy = config.options?.sortBy; if (sortBy === 'year') { return (item: Record<string, unknown>) => { const dateValue = item[config.key]; return dateValue ? new Date(dateValue as string).getFullYear() : undefined; }; } if (sortBy === 'day') { return (item: Record<string, unknown>) => { const dateValue = item[config.key]; return dateValue ? new Date(new Date(dateValue as string).toJSON().split('T')[0]) : undefined; }; } } // Fallback for Number type or Date type without sortBy return config.key; }
Key Benefits
- Compile-time safety: No more accidental
sortByvalues for non-Date types—TypeScript catches mistakes early. - Cleaner code: Type guards eliminate manual type assertions, making the code easier to read and maintain.
- Scalability: If you add a new
SortValueTypelater, just add a new config type and corresponding logic branch.
内容的提问来源于stack exchange,提问作者mchl18




