TypeScript中如何根据参数值正确确定函数返回类型?解决预设参数的函数类型标注问题
applyPreset Function Let's resolve the TypeScript warnings and ensure proper return type deduction for your applyPreset function. The core problem is that TypeScript can't automatically narrow the generic T to distinguish between DatePreset.Custom and other presets, nor can it align the returned value with your conditional return type.
Corrected Code
export enum DatePreset { Today = "Today", ThisMonth = "This month", ThisYear = "This year", Custom = "Custom" } export interface DateRange { from: Date; to?: Date; } export interface DateRangeWithPreset extends DateRange { preset: DatePreset; } // Extract the conditional return type into a reusable alias for clarity type ApplyPresetResult<T extends DatePreset> = T extends DatePreset.Custom ? undefined : Required<DateRangeWithPreset>; export function applyPreset<T extends DatePreset>( preset: T ): ApplyPresetResult<T> { const presets: Record< Exclude<DatePreset, DatePreset.Custom>, Required<DateRange> > = { [DatePreset.Today]: { from: new Date(), to: new Date() }, [DatePreset.ThisMonth]: { from: new Date(), to: new Date() }, [DatePreset.ThisYear]: { from: new Date(), to: new Date() } }; // Explicitly handle the Custom case first if (preset === DatePreset.Custom) { // Assert this return matches the conditional type for Custom return undefined as ApplyPresetResult<T>; } // Narrow the preset type to exclude Custom, so TypeScript recognizes it's a valid key in presets const validPreset = preset as Exclude<DatePreset, DatePreset.Custom>; const readyPreset = presets[validPreset]; // Construct and assert the result matches the conditional return type for non-Custom presets return { preset, ...readyPreset } as ApplyPresetResult<T>; } // Now TypeScript correctly infers the types: const validUndefinedRange = applyPreset(DatePreset.Custom); // Type: undefined const thisYearRange = applyPreset(DatePreset.ThisYear); // Type: Required<DateRangeWithPreset> console.log("validUndefinedRange", validUndefinedRange); console.log("thisYearRange", thisYearRange);
Key Changes Explained
Explicit Custom Branch Handling
By checkingpreset === DatePreset.Customfirst, we give TypeScript a clear code path for theundefinedreturn case. The type assertion tells TypeScript this return value aligns with the conditional type forT = DatePreset.Custom.Narrowing Preset Type
We assertpresetasExclude<DatePreset, DatePreset.Custom>after the Custom check. This lets TypeScript know thatvalidPresetis definitely a key present in thepresetsrecord, eliminating the indexing error.Reusable Return Type Alias
ExtractingApplyPresetResult<T>makes the code cleaner and ensures consistency between the function's return type annotation and the assertions inside the function.Result Type Assertion
Finally, we assert the constructed result object matches theApplyPresetResult<T>type. This bridges the gap between TypeScript's ability to infer the object's structure and your conditional return type requirement.
Now all TypeScript and ESLint warnings should be gone, and the return types will be correctly inferred for every call to applyPreset.
内容的提问来源于stack exchange,提问作者Lawine

