携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
1. 引言
接下来我们将开启新的篇章继续Ts困难篇的题型练习
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md
提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
2. 题型
- 简单的 Vue 类型: 实现类似Vue的类型支持的简化版本。 通过提供一个函数SimpleVue(类似于Vue.extend或者defineComponent),它应该正确地推断出 computed 和 methods 内部的this类型。
在此挑战问题中,我们假设SimpleVue接受只带有data,computed和methods字段的Object作为其唯一的参数,
-data是一个简单的函数,它返回一个提供上下文this的对象,但是你无法在data中获取其他的计算属性或方法。
-computed是将this作为上下文的函数的对象,进行一些计算并返回结果。在上下文中应暴露计算出的值而不是函数。
-methods是函数的对象,其上下文也为this。函数中可以访问data,computed以及其他methods中的暴露的字段。 computed与methods的不同之处在于methods在上下文中按原样暴露为函数。
SimpleVue的返回值类型可以是任意的。
const instance = SimpleVue({
data() {
return {
firstname: 'Type',
lastname: 'Challenges',
amount: 10,
}
},
computed: {
fullname() {
return this.firstname + ' ' + this.lastname
}
},
methods: {
hi() {
alert(this.fullname.toLowerCase())
}
}
})
思路: 首先定义一个SimpleVue方法,该方法接收的参数是一个对象,也就是 data、computed、methods 这些都为参数,这题考的就是这些方法的类型的设定; 那么我们根据泛型来接受它的参数,再通过题目的意思一一返回:定义一个计算属性,该属性为函数方法回抛值就是我们的计算属性值,返回this;data则是返回一个提供上下文 this 的对象;作为上下文的函数的对象,进行一些计算并返回结果,因此需要返回 computed 和 This,ThisType 是内置的方法;methods作为方法可以访问GetComputed, 及data中的字段,向外抛出。该题解答完成,结束。
解答:
type GetComputed<TComputed> = {
[key in keyof TComputed]: TComputed[key] extends () => infer Result ? Result : never;
};
type Options<TData, TComputed, TMethods> = {
data: (this: void) => TData;
computed: TComputed & ThisType<TData>;
methods: TMethods & ThisType<TData & GetComputed<TComputed> & TMethods>;
};
declare function SimpleVue<TData, TComputed, TMethods>(
options: Options<TData, TComputed, TMethods>
): unknown;
传递给Currying的函数可能有多个参数,您需要正确键入它。
在此挑战中,curried函数一次仅接受一个参数。分配完所有参数后,它应返回其结果。
const add = (a: number, b: number) => a + b
const three = add(1, 2)
const curriedAdd = Currying(add)
const five = curriedAdd(2)(3)
思路: 首先,函数柯里话代表的是键多个参数的函数转换为一个带有参数的函数的一个序列的方法,那我我们开始解题时先把对象参数转为函数,再把函数入参拿来开始解构,判断,当解构的值在拿来递归操作知道函数序列生成,该题完成。结束。 解答:
type Impl<Fn> = Fn extends ((...arg: infer Arg) => infer R)
? Arg extends [infer F, ...infer Rest]
? (k: F) => Impl<(...arg: Rest) => R>
: R
: never;
declare function Currying<Fn>(fn: Fn): Impl<Fn>;