TypeScript:如何实现对象类型与回调函数类型的自动双向转换?
Hey there! Let's break down how to solve this type conversion problem you're facing, and also fix the issues with your initial attempts.
First, Let's Fix Your Initial Mistakes
Before diving into solutions, let's clarify why your original approach didn't work:
- Using
Parameters<MyObject>is invalid: The built-inParameters<T>utility only works with function types, not object types. It's designed to extract the parameter tuple from a function, so passing an object type here will throw a TypeScript error. - Your array-to-object type didn't produce the expected result: When you pass a named tuple like
[one: string, two: number, three: boolean]toConvertArrayIntoObject, thekeyof Tfor a tuple returns numeric indices (0,1,2) plus built-in tuple properties likelength—not the parameter labelsone/two/three. Those labels are just syntax sugar in TypeScript; they don't exist as actual keys in the tuple's type system.
Solution 1: Generate Callback Type from Object Type
The cleanest approach (since you want to maintain a single source of truth) is to define your object type first, then derive the callback type from it. Here are two ways to do this:
Option A: Multi-parameter Callback (Matching Object Property Names)
If you want the callback to have individual parameters matching your object's property names and types:
// Your single source of truth type MyObject = { one: string; two: number; three: boolean; }; // Derive the callback type type MyCallback = ( one: MyObject['one'], two: MyObject['two'], three: MyObject['three'] ) => void;
This keeps parameter names aligned with your object's keys, and any changes to MyObject will automatically update MyCallback.
Option B: Destructured Object Parameter (More Maintainable)
For a cleaner, more scalable approach (especially if your object grows), use a destructured object parameter:
type MyObject = { one: string; two: number; three: boolean; }; // Derive callback type with destructured params type MyCallback = ({ one, two, three }: MyObject) => void;
This avoids repeating parameter names manually and scales seamlessly as you add/remove properties from MyObject.
Solution 2: Generate Object Type from Callback Type
If you need to go the other way (start with a callback and get an object type), here's how to do it:
Option A: Manual Mapping (Preserves Property Names)
Since TypeScript can't extract parameter labels from a function type (they're just syntax sugar), you'll map the callback's parameter types to your object's properties explicitly:
// Your single source of truth type MyCallback = (one: string, two: number, three: boolean) => void; // Derive the object type type MyObject = { one: Parameters<MyCallback>[0], two: Parameters<MyCallback>[1], three: Parameters<MyCallback>[2] };
Parameters<MyCallback> extracts the callback's parameter tuple, and we map each tuple index to an object property.
Option B: Generic Utility (For Dynamic Parameter Counts)
If you want a reusable utility to convert any callback's parameters into an object with numeric keys:
type CallbackToObject<T extends (...args: any[]) => void> = { [I in keyof Parameters<T> as `param${I}`]: Parameters<T>[I] }; // Usage type MyCallback = (one: string, two: number, three: boolean) => void; type MyObject = CallbackToObject<MyCallback>; // Result: { param0: string; param1: number; param2: boolean; }
Best Practice
To avoid duplication and keep your types in sync, always define one type first (preferably the object type, since it's more descriptive) and derive the other from it. This way, you only need to update one definition when your data structure changes.
内容的提问来源于stack exchange,提问作者Yash Vyas

