awesome-typescript
awesome-typescript copied to clipboard
「重学TS 2.0 」TS 练习题第五题
第五题
定义一个工具类型 AppendArgument,为已有的函数类型增加指定类型的参数,新增的参数名是 x,将作为新函数类型的第一个参数。具体的使用示例如下所示:
type Fn = (a: number, b: string) => number
type AppendArgument<F, A> = // 你的实现代码
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
请在下面评论你的答案
5.1 使用 Parameters 和 ReturnType 工具类型
type AppendArgument<F extends (...args: any) => any, A>
= (x: A, ...args: Parameters<F>) => ReturnType<F>
type Fn = (a: number, b: string) => number
type FinalF = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
5.2 使用 infer 方式
type AppendArgument<F, T> = F extends (...args: infer Args) => infer Return ?
(x: T, ...args: Args) => Return : never
type Fn = (a: number, b: string) => number
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
延伸阅读:用上这几招,轻松实现 TS 类型提取
Parameters 和 ReturnType 也是使用 infer 实现
Parameters 和 ReturnType 也是使用 infer 实现 对滴,infer 还是蛮有用的,后面的挺多题目也都有用到它。
type Fn = (a: number, b: string) => number type AppendArgument<F, A> = // 你的实现代码 type FinalFn = AppendArgument<Fn, boolean>
type AppendArgument<F extends (...args: any[]) => any, A> = (a: A, ...args: Parameters<F>) => ReturnType<F>;
type Fn = (a: number, b: string) => number
// 使用infer推断 infer要配合extends使用
type AppendArgument<F extends (...args: any) => any, A> = F extends (
...args: infer P
) => infer R
? (x: A, ...args: P) => R
: never
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args: any) => any, A> = (x: A, ...arg: Parameters<F>) => ReturnType<F>
// 测试用例
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args: any) => any, A> = (x: boolean, ...arg: F extends (...args: infer P) => any
? P : never) => F extends (...args: any) => infer P
? P : never
// 测试用例
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
// 定义一个工具类型 AppendArgument,为已有的函数类型增加指定类型的参数,新增的参数名是 x,将作为新函数类型的第一个参数。具体的使用示例如下所示:
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args: any[]) => any, A> = (x: A, ...args: Parameters<F>) => ReturnType<F>;
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
这个题较为简单,利用自带的 Parameters, ReturnType 分别去获取F的参数和返回值类型。 泛型 F 定义一个通用的函数类型约束即可。
此答案对本题做了优化: 使用元组类型支持新增多个前置参数
/**
* 以函数类型 F,并新增以元组类型为 T 的多个前置参数构造新类型
*/
type Fn = (a: number, b: string) => number;
// 定义非空元组约束类型
type NonEmptyTuple = [unknown, ...unknown[]];
// 1. 使用 Parameters 和 ReturnType 工具类型实现
type AppendArgument<F extends (...arg: any) => any, T extends NonEmptyTuple> = (
...args: [...T, ...Parameters<F>]
) => ReturnType<F>;
type FinalFn = AppendArgument<Fn, [boolean, number]>;
// (args_0: boolean, args_1: number, args_2: number, args_3: string) => number
// 2. 使用 infer 方式实现
// 非空元组类型
type AppendArgument<F, T extends NonEmptyTuple> = F extends (
...args: infer Args
) => infer Reture
? (...args: [...T, ...Args]) => Reture
: never;
type FinalFn = AppendArgument<Fn, [boolean, number]>;
// (args_0: boolean, args_1: number, args_2: number, args_3: string) => number
type Fn = (a: number, b: string) => number;
type AppendArgument<F extends (...args: any) => any, A> = ( x: A, ...args: Parameters<F> ) => ReturnType<F>;
type AppendArgument2<F, T> = F extends (...args: infer Args) => infer Return ? (x: T, ...args: Args) => Return : never;
type FinalFn = AppendArgument<Fn, boolean>; type FinalFn2 = AppendArgument2<Fn, boolean>;
type Fn = (a: number, b: string) => number type AppendArgument<F, A> = F extends (...args: infer C) => infer B ? ( (x: A, ...args: C) => B ) : never
type FinalFn = AppendArgument<Fn, boolean> // (x: boolean, a: number, b: string) => number
type AppendArgument<F extends Function, A> = F extends (...args: infer G) => infer R ? (x: A, ...arg: G) => R : never
type Fn = (a: number, b: string) => number
type FinalFn = AppendArgument<Fn, boolean>
type Fn = (a: number, b: string) => number // 泛型T被约束为是一个函数类型 args:Parameters 用来提取函数的参数 返回一个元祖 ReturnType用来获取函数的返回值类型 type AppendArgument<F extends (.....args:any) =>any, A> = (x:A,...args:Parameters<F>)=>ReturnType(F)
type FinalFn = AppendArgument<Fn, boolean>
解题思路
以终为始,这个工具最终要返回一个新函数类型,这个新类型只比老类型多了一个参数;
因此,就必须确保其他参数原封不动传给新函数;
这就可以用到infer关键字;
infer可以在extends的条件语句中,定义一个变量,供其他地方使用。
直接看代码吧,不难:
type AppendArgument<F, T> = F extends (...args: infer Args) => infer Return ?
(x: T, ...args: Args) => Return : never
// 字符串模式匹配 存储靠infer type Fn = (a: number, b: string) => number type AppendArgument<F, A> = F extends (...args: infer Params) => infer Ret ? (x: A, ...args: Params) => Ret : never
type FinalFn = AppendArgument<Fn, boolean> // (x: boolean, a: number, b: string) => number
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args: any[]) => any, addedType> = (x: addedType, ...args: Parameters<F>) => ReturnType<F>;
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
感觉这样实用点,一般是往后插一个或多个参数。
type Fn = (a: number, b: string) => number;
type AppendArgument<F extends (...args: any[]) => any, A extends unknown[]> =
(...args: [...Parameters<F>, ...A]) => ReturnType<F>;
type AppendFn = AppendArgument<Fn, [c: number, x: unknown]>; // (a: number, b: string, c: number, x: unknown) => number
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args:any) => any, A> = F extends (...args:infer P) => infer R ? (x:A, ...arg:P) => R : never
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
/*
思路
1. 首先将F约束为函数类型
2. infer推导类型并保存到P,R上
3. 如果真,参数类型为(x:A, a:number, b: number) => A | number,否则为never
*/
type Fn = (a: number, b: string) => number
type AppendArgument<F extends (...args:any) => any, A> = (x:A, ...arg:Parameters<F>) => ReturnType<F>
type FinalFn = AppendArgument<Fn, boolean>
// (x: boolean, a: number, b: string) => number
/*
思路
1. Parameters<T>用于获取函数参数类型组成的元组
2. ReturnType<T>用于获取函数的返回值类型
*/
type AppendArgument<F, Argument> = F extends (a: infer A, b: infer B) => infer R ? (x: Argument, a: A, b: B) => R : never
type Fn = (a: number, b: string) => number;
type AppendArgument<F, A> = F extends (...args: any) => any ? (x: A, ...arg: Parameters<F>) => ReturnType<F> : never; // 你的实现代码
type FinalFn = AppendArgument<Fn, boolean>;
type Fn = (a: number, b: string) => number;
type AppendArgument<F, A> = F extends (...args: any) => any ? (x: A, ...arg: Parameters<F>) => ReturnType<F> : never; // 你的实现代码
type FinalFn = AppendArgument<Fn, boolean>;
type Fn = (a: number, b: string) => number
// typescript是类型体操,不是值体操,不要搞混了;泛型是类型;
// 把TS当成一门语法,只不过和强类型语法不同的是,它的类型声明在变量后面,并且它支持很复杂的类型声明、定义和别名设置
type AppendArgument1<F extends (...args: any) => any, A> = (x: A, ...args: Parameters<F>) => ReturnType<F>;
type AppendArgument2<F, A> = F extends (...args: infer Args) => infer Return ? (x: A, ...args: Args) => Return : never;
type FinalFn1 = AppendArgument1<Fn, boolean>
type FinalFn2 = AppendArgument2<Fn, string>
type Fn = (a: number, b: string) => number
//方法一
type AppendArgument<F extends (...args:any)=>any, A> = (
X:A,
...args:Parameters<F>
//Parameters获得函数参数类型组合,解构赋值
//ReturnType获得函数返回值类型
)=> ReturnType<F>
//方法二
//通过推断关键字标记点
type AppendArgument2<F, A> = F extends (...args:infer Args)=>infer Return?(x:A,...args:Args)=>Return:never
type FinalFn = AppendArgument<Fn, boolean>
type AppendArgument<F, A> = F extends (...args: infer P) => infer R ? (x: A, ...args: P) => R : F