简体   繁体   中英

"keyof typeof" on Generics

Hello I have some struggle with my generic typing.

interface ReturnValue {
    keyA: string,
    keyB: string
}


interface FilterA {
    keyA: boolean;
}

interface FilterB {
    keyB: boolean;
}


const func = function<T>(args: T) : Pick<ReturnValue, keyof typeof args> {
    const res :Pick<ReturnValue, keyof typeof T> = {};
    Object.keys(args).map(key => {
        res[key] = key
    }) 

    return res;
}

console.log(func({keyB: true}).keyB); // should work
console.log(func({keyA: true}).keyA); // should work

console.log(func({keyA: true}).keyB); // should not work
console.log(func({keyC: true}).keyC); // should not work

But I have this error:

Type 'keyof T' does not satisfy the constraint 'keyof ReturnValue'.
  Type 'string | number | symbol' is not assignable to type 'keyof ReturnValue'.
    Type 'string' is not assignable to type 'keyof ReturnValue'.
      Type 'keyof T' is not assignable to type '"keyB"'.
        Type 'string | number | symbol' is not assignable to type '"keyB"'.
          Type 'string' is not assignable to type '"keyB"'.(2344)

Any ideas?

When I'm using the function call it's working fine, I can access only to what I gave as arguments but TS still display this error.

The context is GraphQl. My input is an object where value of each keys is true or false . From this object I'll build a GQL string query, fetch to api, and the return will have the same structure but value wont be boolean but string for example.

TS Playground

It wort using Array.prototype.reduce and mapped types here:



interface FilterA {
    keyA: boolean;
}

interface FilterB {
    keyB: boolean;
}

type Filters = FilterA | FilterB

type Reduce<Obj> = {
    [Prop in keyof Obj]: Prop
}

const func = <Obj extends Filters>(args: Obj) =>
    Object.keys(args).reduce((acc, key) => ({
        ...acc,
        [key]: key
    }), {} as Reduce<Obj>)

func({ keyB: true }).keyB; // ok
func({ keyA: true }).keyA; // ok

func({ keyA: true }).keyB; // error
func({ keyC: true }).keyC // error

Playground

I have used immutable version of this approach not because it is better. I just prefer immutable data structures.

UPDATE

Code example of alternative version of Reduce from comments:

type Reduce<Obj> = {
    [Prop in keyof Obj]: Prop extends keyof ReturnValue ? ReturnValue[Prop] : never
}


interface ReturnValue {
    keyA: string,
    keyB: string
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM