You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript求助:如何根据枚举类型参数值指定函数的条件返回类型

Fixing Type Alignment for Enum-Dependent Return Types in TypeScript

I see the issue with your function—you're trying to tie the return type directly to the FilterType enum parameter, but TypeScript can't automatically map each switch case's return value to the corresponding ValueReturnType[T] type. Let's fix this with two clean approaches:

Approach 1: Generic Function with Type Assertions

This keeps your original structure but adds targeted type assertions to help TypeScript understand the return type alignment:

export enum FilterType {
  String = 'STRING',
  Number = 'NUMBER',
  StringArray = 'STRING_ARRAY',
  NumberArray = 'NUMBER_ARRAY',
}

type ValueReturnType = {
  [FilterType.String]: string | null
  [FilterType.Number]: number | null
  [FilterType.StringArray]: string[] | null
  [FilterType.NumberArray]: number[] | null
}

function parseQueryFilterValue<T extends FilterType>(
  queryValue: string | string[] | undefined,
  type: T
): ValueReturnType[T] {
  if (!queryValue || typeof queryValue !== 'string') {
    // Assert null matches the return type for the current enum value
    return null as ValueReturnType[T]
  }

  switch (type) {
    case FilterType.Number:
      return +queryValue as ValueReturnType[T]
    case FilterType.String:
      return queryValue as ValueReturnType[T]
    case FilterType.StringArray:
      return queryValue.split('--') as ValueReturnType[T]
    case FilterType.NumberArray:
      return queryValue.split('--').map(el => +el) as ValueReturnType[T]
    default:
      // Add a default case to handle unexpected enum values (prevents TS errors)
      throw new Error(`Unsupported filter type: ${type}`)
  }
}

// Test calls (TS will infer correct return types)
const numResult = parseQueryFilterValue("5", FilterType.Number); // number | null
const strArrResult = parseQueryFilterValue("apple--banana", FilterType.StringArray); // string[] | null

Why this works:

TypeScript can't automatically link the narrowed type in each switch case to the generic T, so we use as ValueReturnType[T] to explicitly tell the compiler that the return value matches the expected type for the current enum input.

Approach 2: Function Overloads (More Explicit)

If you prefer clearer type definitions without assertions, use function overloads to explicitly define the return type for each enum value:

export enum FilterType {
  String = 'STRING',
  Number = 'NUMBER',
  StringArray = 'STRING_ARRAY',
  NumberArray = 'NUMBER_ARRAY',
}

// Overload signatures: Define input-output pairs for each enum value
function parseQueryFilterValue(queryValue: string | string[] | undefined, type: FilterType.String): string | null;
function parseQueryFilterValue(queryValue: string | string[] | undefined, type: FilterType.Number): number | null;
function parseQueryFilterValue(queryValue: string | string[] | undefined, type: FilterType.StringArray): string[] | null;
function parseQueryFilterValue(queryValue: string | string[] | undefined, type: FilterType.NumberArray): number[] | null;

// Implementation signature: Covers all possible return types
function parseQueryFilterValue(
  queryValue: string | string[] | undefined,
  type: FilterType
): string | number | string[] | number[] | null {
  if (!queryValue || typeof queryValue !== 'string') {
    return null
  }

  switch (type) {
    case FilterType.Number:
      return +queryValue
    case FilterType.String:
      return queryValue
    case FilterType.StringArray:
      return queryValue.split('--')
    case FilterType.NumberArray:
      return queryValue.split('--').map(el => +el)
    default:
      throw new Error(`Unsupported filter type: ${type}`)
  }
}

// Test calls (TS infers precise return types automatically)
const strResult = parseQueryFilterValue("hello", FilterType.String); // string | null
const numArrResult = parseQueryFilterValue("10--20--30", FilterType.NumberArray); // number[] | null

Why this works:

Overload signatures act as a contract for TypeScript—when you call the function with a specific FilterType, TS uses the matching overload to infer the correct return type, no assertions needed.

Which Approach to Choose?

  • Use the generic + assertion approach if you want to keep a single return type definition tied to your ValueReturnType interface.
  • Use overloads if you prefer more explicit, self-documenting type definitions that are easier to read for other developers.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 16:27:26