[TypeScript] Type Challenges #3312 - Parameters

63 阅读1分钟

题目描述

实现内置的 Parameters 类型,而不是直接使用它,可参考TypeScript官方文档

例如:

const foo = (arg1stringarg2number): void => {}

type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]

题解

// ============= Test Cases =============
import type { EqualExpect } from './test-utils'

const foo = (arg1stringarg2number): void => { }
const bar = (arg1booleanarg2: { a'A' }): void => { }
const baz = (): void => { }

type cases = [
  Expect<Equal<MyParameters<typeof foo>, [stringnumber]>>,
  Expect<Equal<MyParameters<typeof bar>, [boolean, { a'A' }]>>,
  Expect<Equal<MyParameters<typeof baz>, []>>,
]

// ============= Your Code Here =============
type MyParameters<T extends CallableFunction> = T extends (...args: infer U) => unknown ? U : never

使用T extends CallableFunction对传入的类型参数T进行约束,确保T是一个可调用的函数类型

Function类型只约束了函数的name属性,太宽泛了,不适合检查可调用函数。Function类型的实现如下:

interface Function {
    readonly namestring;
}

CallableFunction是一个扩展了Function的接口,提供了更精确的可调用函数类型描述。CallableFunction类型的实现如下:

interface CallableFunction extends Function {
    apply<T, R>(this(this: T) => R, thisArg: T): R;
    apply<T, A extends any[], R>(this(this: T, ...args: A) => R, thisArg: T, args: A): R;
    call<T, A extends any[], R>(this(this: T, ...args: A) => R, thisArg: T, ...args: A): R;
    bind<T>(this: T, thisArgThisParameterType<T>): OmitThisParameter<T>;
    bind<T, A extends any[], B extends any[], R>(this(this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R;
}

使用T extends (...args: infer U) => unknown将函数T的参数类型存储在U中,如果T是可调用函数,返回U,否则返回never