Home > Net >  Make field type override object generic's type
Make field type override object generic's type

Time:09-22

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

Playground Link

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.

Playground


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

Playground

  • Related