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
ValueReturnTypeinterface. - Use overloads if you prefer more explicit, self-documenting type definitions that are easier to read for other developers.
内容的提问来源于stack exchange,提问作者FreshBeen

