Skip to main content

6 - 简单的 Vue 类型

Answer TestCases

实现类似Vue的类型支持的简化版本。

通过提供一个函数SimpleVue(类似于Vue.extenddefineComponent),它应该正确地推断出 computed 和 methods 内部的this类型。

在此挑战中,我们假设SimpleVue接受只带有datacomputedmethods字段的Object作为其唯一的参数,

  • data是一个简单的函数,它返回一个提供上下文this的对象,但是你无法在data中获取其他的计算属性或方法。

  • computed是将this作为上下文的函数的对象,进行一些计算并返回结果。在上下文中应暴露计算出的值而不是函数。

  • methods是函数的对象,其上下文也为this。函数中可以访问datacomputed以及其他methods中的暴露的字段。 computedmethods的不同之处在于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())
}
}
})

Solution

type GetComputed<C> = C extends Record<string, (...args: any[]) => any>
? { [S in keyof C]: ReturnType<C[S]> }
: never

declare function SimpleVue<D, C, M>(
options: {
data: () => D
computed: C
methods: M
} & ThisType<D & M & GetComputed<C>>
): any

GetComputed

GetComputed 首先判断泛型 C 是否是对象结构, 其中 key 的类型是 stringvalue 的类型是函数,是对象结构,则返回对象类型, keyCkey, 类型则是 key 对应的函数的返回类型

如:

type GetComputed<C> = C extends Record<string, (...args: any[]) => any>
? { [S in keyof C]: ReturnType<C[S]> }
: never

type ComputedType = GetComputed<{
data: () => number
}>

ComputedType 类型是

{
data: number
}

ThisType

在 ts 中使用 this 时, 会自动推导其在当前上下文中的类型。

如:

type OptionType = {
value: number
methods: {
getOption: () => number
}
}
const option = {
value: 2,
methods: {
getOption: function (): number[] {
return this.value // Property 'value' does not exist on type '{ getOption: () => number; }'.t
}
}
}

定义变量 option 时会报错, 因为 this 的类型 被推导为

this: {
getOption: () => number
}

因此需要指定 this 类型,使用 ThisType<T>

type OptionType = {
value: number
methods: {
getOption: () => number
}
} & ThisType<OptionType>

回到 SimpleVue 类型定义中

  • this 可以在任意的 key 中使用,因此需要通过 ThisType<T> 指明 this 的类型

  • methods 中可以通过 this 直接访问 computed 中的属性,而不是调用方法, 因此需要把 computed 类型从 { key: function} 转换成 { key: ReturnType<function> }