Home > Back-end >  Infer Object Generic from its propery (return function type)
Infer Object Generic from its propery (return function type)

Time:01-31

I want to make an interface that can infers a type T from the return value of the function data so the function step can receive as a parameter the type of this.

Something like this:

type DefInstance = {
    
    x : number,
    y : number,
};

type StateInstance<T> = {
    data : () => T,
    step : (this : DefInstance & T, turn : number) => boolean,
};

const instance : StateInstance<{
    f : number
}> = {
    data : () => ({
        f : 0,
    }),
    step : function(turn){
        this.f  ;
        
        if(this.f > 3){
            this.x  = 1;
            this.f = 0;
        }
        console.log(`move on turn ${turn}`);          
        return true;
    }
}

But without having to specify the type.

/*
  stuff from above
*/

//so it looks like this
const instance : StateInstance = {
    data : () => ({
        f : 0,
    }), //here i define the function and the return value
    step : function(turn){
        this.f  ; //here i access the members described in the return value of data
        
        if(this.f > 3){
            this.x  = 1;
            this.f = 0;
        }
        console.log(`move on turn ${turn}`);          
        return true;
    }
}

similar to what is made in Vue.js (v3) with the data function, where all methods can access the members of the state of the component

/*vue stuff*/
export default defineComponent({
  data : () => ({ count : 10 }),
  methods : {
    countUp() { this.count  ; } //Autocompleted property `count` when access `this`
  }
})

I know that Vue uses a function (that uses lots of generics behind), but i want to know how to to do it using only a type (or interface) (if posible). Or, if its only doable using functions, how to do it with a function.

CodePudding user response:

If you need to reuse that magic function vera mentioned, you can make the type constructor generic:

import { apply } from 'free-types'

const of = <$T extends Type<1>>() => <T>(i: apply<$T, [T]>) => i;

const State = of<$StateInstance>();

const instance = State({
    data : () => ({
        f : 0,
    }), //here i define the function and the return value
    step : function(turn){
        this.f  ; //here i access the members described in the return value of data
        
        if(this.f > 3){
            this.x  = 1;
            this.f = 0;
        }
        console.log(`move on turn ${turn}`);          
        return true;
    }
})

$StateInstance can be defined like so

interface $StateInstance extends Type<1> {
   type: StateInstance<this[0]>
}

Or, if you don't need StateInstance for anything else:

interface $StateInstance extends Type<1> {
    type: { [K in 'data'|'step']: this[K] }
    data : () => this[0],
    step : (this : DefInstance & this[0], turn : number) => boolean,
};

playground

  • Related