See example. I have type TConfig
. I want to get suggestions of available fields in function parameter. This is example for working with redux store(reducer, state).
type TParam = any;
type TFunction = (param: TParam) => TParam;
type TConfig = Record<string, {func: TFunction, param: TParam}>;
function handleConfig(config: TConfig) {};
type TMyParam1 = {
prop1: string;
prop2: number;
}
type TMyParam2 = {
prop3: boolean;
prop4: string;
}
handleConfig({
'1': {
func: (param: TMyParam1) => param,
param: {
// I want suggestions of available fields in TMyParam1
}
},
'2': {
func: (param: TMyParam2) => param,
param: {
// I want suggestions of available fields in TMyParam2
}
}
})
In order for this to work, you need handleConfig()
to be generic. Conceptually, for each property key of the config
input ("1"
and "2"
in your example), you want a single property value type that serves as both the type of the param
property, and the input and output type of the func
property (TMyParam1
and TMyParam2
in your example). So let's make it generic in terms of an object type T
corresponding to that shape ({"1": TMyParam1; "2": TMyParam2}
in your example):
function handleConfig<T extends object>(config: { [K in keyof T]: {
func: (param: T[K]) => T[K],
param: T[K]
} }) { };
So config
's type is a mapped type over the properties of T
.
This basic approach should work (you will get errors when and only when you make a mistake), but it seems you want to be able to get IntelliSense hints when func
is specified but param
is not. And that means you want T
to be inferred only from func
, and then param
is just checked against it, not inferred from it. So you want to block inference on param
, as described in microsoft/TypeScript#14829. The next release of TypeScript should include a native NoInfer<T>
utility type, as implemented at microsoft/TypeScript#56794, at which point you can just write
function handleConfig<T extends object>(config: { [K in keyof T]: {
func: (param: T[K]) => T[K],
param: NoInfer<T[K]>
} }) { };
and things will behave as you expect:
handleConfig({
'1': {
func: (param: TMyParam1) => param,
param: {
// suggests prop1 and prop2
}
},
'2': {
func: (param: TMyParam2) => param,
param: {
// suggests prop3 and prop4
}
}
})
Until that release happens you can define your own NoInfer
utility in a number of ways; here's one that works for this example:
type NoInfer<T> = T extends infer U ? U : never
(You can look at microsoft/TypeScript#14829 for this and other workarounds and explanations for how they work).