问题历史
随着 TypeScript 的发展,自动提取函数返回值类型的需求逐渐增大,特别是在大型项目中涉及多个相互关联的函数时。为此,引入了实用类型 ReturnType<T>,该类型自 TypeScript 2.8 版本起出现在标准库中。
问题
在大型和复杂的项目中,保持类型的及时性可能是一个挑战——如果手动指定每个函数的返回值类型,并且签名发生变化,就很容易出现不一致的情况,即签名和实现不匹配。此外,如果函数返回复杂结构,通常也不容易在所有使用位置手动同步返回值类型的描述。
解决方案
实用类型 ReturnType<T> 自动提取函数的返回类型,并可以在代码的任何位置用于类型化函数调用的结果。这降低了手动维护类型基础设施的工作量,并最小化了由于描述和实际返回值类型不一致而导致的错误。
代码示例:
function createUser(name: string, age: number) { return { name, age, created: new Date() }; } type User = ReturnType<typeof createUser>; // User: { name: string; age: number; created: Date; }
关键特性:
能否将 ReturnType 用于类的方法?
可以,但要记住上下文:如果方法是与函数相关的对象的一个属性,请使用 ReturnType<obj['方法']>。
代码示例:
class MyClass { foo(x: number) { return x * 2; } } type FooReturn = ReturnType<MyClass['foo']>; // 类型错误! // 应这样: type FooReturn = ReturnType<(x: number) => number>; // number // 或将方法提取为函数: const obj = new MyClass(); type FooReturn2 = ReturnType<typeof obj.foo>;
ReturnType 对于 void/never 的函数会返回什么?
对于声明返回类型为 void 的函数,ReturnType 将返回 void。对于 never 类型 — 将返回 never。
代码示例:
function doNothing(): void {} type Result = ReturnType<typeof doNothing>; // void
ReturnType 能否与函数重载一起使用?
不能,ReturnType 提取的是 "实现" 的返回类型,而不是所有重载的返回类型。如果有多个重载,则选择描述的实现类型。
代码示例:
function func(x: number): number; function func(x: string): string; function func(x: any): any { return x } type RT = ReturnType<typeof func>; // any
在项目中为函数返回对象声明了手动类型。函数发生变更 — 类型未更新,调用在运行时失败。
优点:
缺点:
转向在使用函数返回值的所有地方使用 ReturnType。在更改的情况下,类型始终是最新的。
优点:
缺点: