You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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 sortBy values 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 SortValueType later, just add a new config type and corresponding logic branch.

内容的提问来源于stack exchange,提问作者mchl18

火山引擎 最新活动