获取函数/类构造函数的参数类型

Posted

技术标签:

【中文标题】获取函数/类构造函数的参数类型【英文标题】:Get argument types for function / class constructor 【发布时间】:2017-09-14 20:15:50 【问题描述】:

我正在尝试做一些我不确定在 TypeScript 中是否可行的事情:从函数中推断参数类型/返回类型。

例如:

function foo(a: string, b: number) 
  return `$a, $b`;


type typeA = <insert magic here> foo; // Somehow, typeA should be string;
type typeB = <insert magic here> foo; // Somehow, typeB should be number;

我的用例是尝试创建一个包含构造函数和参数的配置对象。

例如:

interface IConfigObject<T> 
    // Need a way to compute type U based off of T.
    TypeConstructor: new(a: U): T;
    constructorOptions: U;


// In an ideal world, could infer all of this from TypeConstructor

class fizz 
    constructor(a: number) 


const configObj : IConfigObj = 
    TypeConstructor: fizz;
    constructorOptions: 13; // This should be fine


const configObj2 : IConfigObj = 
    TypeConstructor: fizz;
    constructorOptions: 'buzz'; // Should be a type error, since fizz takes in a number

【问题讨论】:

【参考方案1】:

Typescript 现在具有 ConstructorParameters 内置函数,类似于 Parameters 内置函数。确保传递的是类类型,而不是实例:

ConstructorParameters<typeof SomeClass>

ConstructorParameter Official Doc

Parameters Official Doc

【讨论】:

效果很好!如果 SomeClass 的构造函数将对象作为第一个参数,则获取对象类型的语法为ConstructorParameters&lt;typeof SomeClass&gt;[0] 非常感谢,我喜欢 TypeScript。 但是我们在SomeClass 上有一个通用参数呢?我试过ConstructorParameters&lt;typeof SomeClass&lt;T&gt;&gt;,但发现它的语法无效。【参考方案2】:

使用 TypeScript 2.8,您可以使用新的 extends 关键字:

type FirstArgument<T> = T extends (arg1: infer U, ...args: any[]) => any ? U : any;
type SecondArgument<T> = T extends (arg1: any, arg2: infer U, ...args: any[]) => any ? U : any;

let arg1: FirstArgument<typeof foo>; // string;
let arg2: SecondArgument<typeof foo>; // number;
let ret: ReturnType<typeof foo>; // string;

【讨论】:

有没有办法从重载函数中提取参数类型?【参考方案3】:

Typescript 2.8 添加了conditional types with type inference

Typescript 3.0 添加了rest-elements-in-tuple-types,因此您现在可以获取Array 类型中的所有参数。

type ArgumentsType<T extends (...args: any[]) => any> = T extends (...args: infer A) => any ? A : never;

type Func = (a: number, b: string) => boolean;
type Args = ArgumentsType<Func> // type Args = [number, string];
type Ret = ReturnType<Func> // type Ret = boolean;

你可以这样使用它:

const func = (...args: Args): Ret =>  // type the rest parameters and return type
  const [a, b] = args; // spread the arguments into their names
  console.log(a, b); // use the arguments like normal
  return true;
;

// Above is equivalent to:
const func: Func = (a, b) => 
  console.log(a, b);
  return true;

【讨论】:

【参考方案4】:

我将为提取构造函数参数类型的用例提供更直接的答案。

type GetConstructorArgs<T> = T extends new (...args: infer U) => any ? U : never

class Foo 
    constructor(foo: string, bar: number)
        //
    


type FooConstructorArgs = GetConstructorArgs<typeof Foo> // [string, number]

【讨论】:

【参考方案5】:

这个方法怎么样:

interface IConfigObject<T, U> 
    TypeConstructor: new(a: U) => T;
    constructorOptions: U;


class fizz 
    constructor(a: number) 


function createConfig<U, T>(cls:  new (arg: U): T , arg: U): IConfigObject<T, U> 
    return 
        TypeConstructor: cls,
        constructorOptions: arg
    


const configObj = createConfig(fizz, 3); // ok
const configObj2 = createConfig(fizz, "str"); // error

(code in playground)


编辑

你可以有一个索引类型变量:

const configs:  [name: string]: IConfigObject<any, any>  = 
    config1: createConfig(fizz, 3),
    config2: createConfig(fizz, "str"), // error
    config3: createConfig(buzz, "str")

【讨论】:

这绝对可以。有没有办法让它作为索引签名工作?例如: const configs : SomeType = config1: TypeConstructor: fizz, constructorOptions: 3, , config2: TypeConstructor: fizz, constructorOptions: 'str', // 应该抛出错误 config3: TypeConstructor: buzz, constructorOptions: 'str', 当然。检查我修改后的答案

以上是关于获取函数/类构造函数的参数类型的主要内容,如果未能解决你的问题,请参考以下文章

常见的构造函数类型

java怎么调用带参数构造函数

Flutter 6种构造函数详解

我应该将啥类型添加到作为参数接收的类构造函数中?

java类的构造函数的参数为接口类型,如何传值?

类5(转换构造函数)