Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

All to make a conditional type with all possible generics?

I have this types:

type IInputType = "text" | "checkbox" | "number";

type IField<T extends IInputType> = {
  name: string;
  value: 
   T extends "checkbox" ? boolean : 
   T extends "number" ? number : 
   string;
  type: T;
};

type IPossibleFieldTypes = IField<IInputType>;

That way the conditional is not working because field.value is typed as string, number or boolean, and not only boolean as should:

 // field type is IPossibleFieldTypes 
 if (field.type === "checkbox") {
  // Here field.value should only be boolean
  // but TS are allowing string or number too
 }

But if I specify the possible IFields manually:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

type IPossibleFieldTypes =
  | IField<"text">
  | IField<"checkbox">
  | IField<"number">;

Now the types are being displayed correctly:

 if (field.type === "checkbox") {
  // Here field.value can only be boolean
 }

The question is:

There is a way to make this type work (IPossibleFieldTypes) without have to manually set the possible generics?

>Solution :

Make IField a distributive conditional type, so that you make a discriminated union:

type IInputType = keyof ValueMap;

type ValueMap = {
    text: string;
    checkbox: boolean;
    number: number;
};

type IField<T extends IInputType> = T extends T ? {
    name: string;
    value: ValueMap[T];
    type: T;
} : never;

Also, we take advantage of the fact that T is a string, which means instead of a long chain of conditional types, we can use another type that maps T to the right type. Then narrowing will work correctly:

if (field.type === "checkbox") {
    field.value;
    //    ^? boolean
}

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading