Distributed conditional types

When defining a conditional type, we can also use distributive syntax to return one of a number of types. As an example of this, consider the following function definition:

function compareTwoValues(  
    input : string | number | Date, 
    compareTo : string | number | Date ) { 
} 

Here, we have defined a function named compareTwoValues that has two parameters, input and compareTo. Both the input and the compareTo parameters can accept either a string or a number or a Date type. But what if we wanted to apply the following rules:

  • If the input parameter is of type Date, then only allow the compareTo parameter to be of type Date
  • If the input parameter is of type number, then allow the compareTo parameter to be of type number or Date
  • If the input parameter is of type string, then allow the compareTo parameter to be either type number, Date or string

Implementing this logic is where distributed conditional types come in handy, as follows:

type dateOrNumberOrString<T> =  
    T extends Date ? Date : 
    T extends number ? Date | number : 
    T extends string ? Date | number | string : never; 

Here, we have a conditional type named dateOrNumberOrString. The first condition states that if T is of type Date, then return a type of Date. The second condition states that if T is of type number, then return a type of Date or number, and the final condition states that if T is of type string, then return a type of Date or number or string. If none of these conditional types are found, then return a type of never. We can now use this distributed conditional type in a function definition, as follows:

function compareValues<T extends string | number | Date | boolean> 
    (input: T, compareTo : dateOrNumberOrString<T>) { 
    // do the comparison 
}

Here, we have defined a function named compareValues that is using a distributed type for the type of T, and which allows the type of T to be either a string, number, Date, or boolean type. The input parameter is of type T, and the compareTo parameter is now using our distributed conditional type dateOrNumberOrString. We now have some design time rules in place for code that calls this function. Let's test this design using Date types as follows:

compareValues(new Date(), new Date()); 
compareValues(new Date(), 1); 
compareValues(new Date(), "1"); 

Here, we call the compareValues function with a Date type as the first argument. The first call to compareValues is legal, as the nature of the second argument is of type Date. The second and third calls to compareValues, however, will both cause compilation errors as follows:

error TS2345: Argument of type '1' is not assignable to parameter of type 'Date'.
error TS2345: Argument of type '"1"' is not assignable to parameter of type 'Date'.

Here, we can see that the compiler will not allow the compareTo argument to be of type number or of type string if the input argument is of type Date. Let's further test our distributed conditional type with numbers, as follows:

compareValues(1, 1); 
compareValues(1, Date.now()); 
compareValues(1, "1"); 

Here, the type of the input argument is number, and we are calling the compareTo function with a type of number, then Date, and then string. The first two calls are legal, according to our logic, but the last call will generate an error:

error TS2345: Argument of type '"1"' is not assignable to parameter of type 'Date'.

Finally, let's break all of the rules, and call our compareTo function with a type of boolean, as follows:

compareValues(true, "test");

Here, the type of our input argument is boolean. Note that our function definition allows this, as the type of T can be of type string, number, Date or boolean. The distributed conditional type, however, does not, and will therefore generate the following error:

error TS2345: Argument of type '"test"' is not assignable to parameter of type 'never'.  

So our distributed conditional type is checking the input argument, which is of type boolean, not matching any of our conditions, and therefore returning a type of never. Our function design has held up, even though we might have made a mistake in allowing the input argument to be of type boolean.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.83.240