Yuzhe's Blog

yuzhes

Simple Vue

Posted at # TypeScript # TypeChallenge # TC-Hard
EN ·

Simple Vue

Problem Link

Problem

Implement a simplified version of a Vue-like defineComponent function that accepts an options object with data, computed, and methods properties. Each of these should have proper access to this:

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

The key challenge is that this in each section must refer to different merged contexts.

declare function SimpleVue<D, C extends Record<string, () => any>, M>(options: {
  data(this: void): D
  computed: C & ThisType<D>
  methods: M & ThisType<D & { [K in keyof C]: ReturnType<C[K]> } & M>
}): any

How it works:

  1. data(this: void) — prevents accidental this usage inside data, since it should be a pure factory.
  2. computed: C & ThisType<D> — computed functions can access data fields via this.
  3. methods: M & ThisType<D & ComputedValues & M> — methods can access data, computed return values, and other methods.
  4. { [K in keyof C]: ReturnType<C[K]> } — maps each computed property to its return type, simulating how Vue exposes computed as plain properties on the instance.

ThisType<T> is a built-in TypeScript utility that sets the type of this inside an object literal when used with noImplicitThis.

Key Takeaways