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,
};