typescript 类型体操 之 191-medium-append-argument

258 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

前言

在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,在上一篇文章中,我们完成了中等的第十五题,今天来做中等的第十六题 191-medium-append-argument

下面这个是类型体操github仓库:

type-challenges/type-challenges: Collection of TypeScript type challenges with online judge (github.com)

191-medium-append-argument

image.png

import type { Equal, Expect } from '@type-challenges/utils'

type Case1 = AppendArgument<(a: number, b: string) => number, boolean>
type Result1 = (a: number, b: string, x: boolean) => number

type Case2 = AppendArgument<() => void, undefined>
type Result2 = (x: undefined) => void

type cases = [
  Expect<Equal<Case1, Result1>>,
  Expect<Equal<Case2, Result2>>,
]

从README和测试用例中能够得出,我们需要实现一个工具函数 AppendArgument 能够为一个函数类型新增入参

实现 AppendArgument

在这之前我们知道,通过 ...arginfer 相互配合能够用一个数组提取出函数的所有入参:

type APPENDARG1 = ((a: number, b: string) => number) extends (...arg:infer Rest)=>infer End ? Rest : never
// type APPENDARG1 = [a: number, b: string]

并且相反的,我们能够为 ...arg 提供一个数组类型,用于作为函数的入参

type APPENDARG2 = (...arg:[a:1,b:2,c:3]) => number
// type APPENDARG2 = (a: 1, b: 2, c: 3) => number

那么知道这些之后,这道题就变得很简单了,我们只需要用 infer 获取原有的参数然后用一个数组把旧参数和新参数组合到一起。

type AppendArgument<Fn, A> = Fn extends (...arg: infer Rest) => infer End
  ? (...arg: [...Rest, A]) => End
  : Fn;

type Case1 = AppendArgument<(a: number, b: string) => number, boolean>;
// type Case1 = (arg_0: number, arg_1: string, arg_2: boolean) => number

这样测试用例就能够全部通过了

知识点

关于上述提到了部分的知识点:

  1. Rest 参数
  2. infer 关键字

对于函数来说,灵活的运用 Rest 参数是非常重要的,通过灵活的运用 Rest 参数和 infer 关键字,我们就能够实现大部分的函数类型修改。

总结

今天我们做完了中等的第十六题,题目具体的关键还是在于如何灵活使用 Rest 参数来获取函数的入参以及设置函数的入参。