Basically what I want to happen is that the type of T(generic) be the listener's(listener field) type, that way no metter if listener is either the default value or a custom one, I'd have auto completion for "firstParatemer", is that possible? If not, is there any other way around other than setting everything to any?
Right now I can only have one type at once, either dummy or upper, not both.
Code:
const upper = ({ helloWorld }: { helloWorld: string }) =>
helloWorld.toUpperCase();
const dummy = ({ worldHello }: { worldHello: string }) => worldHello;
type objType<T extends (...args: any[]) => any = typeof upper> = {
listener?: T;
firstParameter: Parameters<T>[0];
};
const obj: objType = {
listener: upper,
firstParameter: {
helloWorld: "hello world", // auto completion
},
};
let arr: objType[] = [
obj,
{ listener: dummy, firstParameter: { worldHello: "world hello" } },
]; // what I want
let dummyObj: objType = {
listener: dummy,
firstParameter: {
// i want auto completion here without having to specify the type with objType<typeof dummy>
}
}
CodePudding user response:
What you want isn't directly possible, but you can create a union of the possible values instead:
type makeObjType<fns extends (...args: any[]) => any> = fns extends fns ? {
listener?: fns;
firstParameter: Parameters<fns>[0];
} : never;
type objType = makeObjType<typeof upper | typeof dummy>;
We use fns extends fns
to utilize distributive conditional types. Then we just make the possible values with them.
To make it work with any function, you'll have to use a helper generic function to do the inference for us:
function makeObj<fn extends (...args: any[]) => any>(obj: {
listener: fn;
firstParameter: Parameters<fn>[0];
}) {
return obj;
}
and then you can use any function with it:
const o = makeObj({
listener: (ok: string) => ok,
firstParameter: "must be string",
});