Home > Net >  "Not in keyof" in Typescript generics
"Not in keyof" in Typescript generics

Time:06-10

Creates a type where each property from Type is now of type boolean:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

Now I want to extend this: All properties not in Type, if present, must be of type string. Something like this:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
  [Property not in keyof Type]?: string;
};

What is the correct approach to this?

CodePudding user response:

A stand-alone type will probably not work here. What you are looking for is basically this:

type OptionsFlag<T> = {
  [K in keyof T]: boolean
} & {
  [K in Exclude<string, keyof T>]: string
}

But this does not work (yet) in TypeScript. Because Exclude<string, keyof T> evaluates down to string and will be an index signature. You can not construct an object with this type because every property's type will have to fulfill both index signature requirements string & boolean which is not possible.

The only work-around I could think of is this:

type Type = {
  a: string
  b: string
  c: string
}

type OptionsFlag<T, S> = {
  [K in keyof T]: K extends keyof S ? boolean : string
}

function f<T>(obj: OptionsFlag<T, Type>) {}

f({
  a: true,
  b: true,
  c: "abc", // error because c is in Type and string
  d: "abc",
  e: "abc",
  f: true   // error because f is not in type and boolean
})

Playground

We can use a generic type of a function to map over each property of the passed type T. We then check for each property of T if it belongs to S and ajust the type accordingly.

This has a major drawback: The type of S must be known when we declare the function. As you can see, I put the type Type in OptionsFlag<T, Type> in the function declaration instead of using a second generic type. TypeScript does not yet support partial type inference, so we can't let TypeScript infer T and manually specify a second generic type when we call the function.

CodePudding user response:

Since the mapped type can only access keys live within Type, you need to provide an extra Generic Type for comparison.

type OptionsFlags<T extends {}, K extends string> = {
  [k in K]: k extends keyof T ? boolean : string;
};
  • Related