In my code, there is a function called createModule
that simply returns its parameter.
function createModule(obj) {
return obj
}
The returned value must be of the same type as the parameter provided:
interface Mod1State {
p1: string
}
const mod1 = createModule({
namespaced: true,
state: {
p1: "abc"
} as Mod1State,
mutations: {
SET_P1(state, p1: string) {
state.p1 = p1
}
}
} as const)
// The expected type of 'mod1' should be: '{ namespaced: true, state: Mod1State, mutations: { SET_P1(state: any, p1: string): void } }'
Initially, achieving this requirement seems straightforward:
function createModule<T>(obj: T): T {
return obj
}
Now, I want to introduce auto-completion for the state
parameter within the SET_P1
function and prefer checking the state
property instead of using casting.
SET_P1(state, p1: string) {
// Here, 'state' should be of type Mod1State
}
This was my attempt:
function createModule<S, T extends WithState<S> = WithState<S>>(obj: VuexModule<T, S>): T {
return obj
}
interface WithState<S> {
state?: S
}
type VuexModule<T extends WithState<S>, S = T["state"]> = T & {
namespaced?: boolean
state?: S
mutations?: {
[K: string]: (state: S, payload: any) => void
}
}
However, it only works if I remove the as const
part (the reason behind this eludes me):
const mod1 = createModule<Mod1State>({
namespaced: true,
state: { // This checks the type of 'state'
p1: "abc"
},
mutations: {
SET_P1(state, p1: string) { // Ensures 'state' has the 'Mod1State' type
state.p1 = p1
}
}
})
But now, the type of mod1
becomes WithState<Mod1State>
. The exact inferred type is lost. How can I restore the precise type of the parameter passed to createModule
to be reflected in the return value?
For further reference, see the playground example in the playground.
EDIT: I managed to get something working from a modified version of my original code. The functioning nature of it perplexes me, especially how the namespaced
type is deduced as true
without the need for as const
, instead of being recognized as a boolean
.