UNPKG

type-fest

Version:

A collection of essential TypeScript types

103 lines (77 loc) 2.8 kB
import type {IsNever} from './is-never.d.ts'; /** An if-else-like type that resolves depending on whether the given `boolean` type is `true` or `false`. Use-cases: - You can use this in combination with `Is*` types to create an if-else-like experience. For example, `If<IsAny<any>, 'is any', 'not any'>`. Note: - Returns a union of if branch and else branch if the given type is `boolean` or `any`. For example, `If<boolean, 'Y', 'N'>` will return `'Y' | 'N'`. - Returns the else branch if the given type is `never`. For example, `If<never, 'Y', 'N'>` will return `'N'`. @example ``` import type {If} from 'type-fest'; type A = If<true, 'yes', 'no'>; //=> 'yes' type B = If<false, 'yes', 'no'>; //=> 'no' type C = If<boolean, 'yes', 'no'>; //=> 'yes' | 'no' type D = If<any, 'yes', 'no'>; //=> 'yes' | 'no' type E = If<never, 'yes', 'no'>; //=> 'no' ``` @example ``` import type {If, IsAny, IsNever} from 'type-fest'; type A = If<IsAny<unknown>, 'is any', 'not any'>; //=> 'not any' type B = If<IsNever<never>, 'is never', 'not never'>; //=> 'is never' ``` @example ``` import type {If, IsEqual} from 'type-fest'; type IfEqual<T, U, IfBranch, ElseBranch> = If<IsEqual<T, U>, IfBranch, ElseBranch>; type A = IfEqual<string, string, 'equal', 'not equal'>; //=> 'equal' type B = IfEqual<string, number, 'equal', 'not equal'>; //=> 'not equal' ``` Note: Sometimes using the `If` type can make an implementation non–tail-recursive, which can impact performance. In such cases, it’s better to use a conditional directly. Refer to the following example: @example ``` import type {If, IsEqual, StringRepeat} from 'type-fest'; type HundredZeroes = StringRepeat<'0', 100>; // The following implementation is not tail recursive type Includes<S extends string, Char extends string> = S extends `${infer First}${infer Rest}` ? If<IsEqual<First, Char>, 'found', Includes<Rest, Char>> : 'not found'; // Hence, instantiations with long strings will fail // @ts-expect-error type Fails = Includes<HundredZeroes, '1'>; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Error: Type instantiation is excessively deep and possibly infinite. // However, if we use a simple conditional instead of `If`, the implementation becomes tail-recursive type IncludesWithoutIf<S extends string, Char extends string> = S extends `${infer First}${infer Rest}` ? IsEqual<First, Char> extends true ? 'found' : IncludesWithoutIf<Rest, Char> : 'not found'; // Now, instantiations with long strings will work type Works = IncludesWithoutIf<HundredZeroes, '1'>; //=> 'not found' ``` @category Type Guard @category Utilities */ export type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch; export {};