File tree 2 files changed +47
-0
lines changed
2 files changed +47
-0
lines changed Original file line number Diff line number Diff line change @@ -8,6 +8,18 @@ import { ObjectType } from "./objects";
8
8
*/
9
9
export type NoInfer < T > = T & ObjectType < T > ;
10
10
11
+ /**
12
+ * Prevent `T` from being distributed in a conditional type.
13
+ * A conditional is only distributed when the checked type is naked type param and T & {} is not a
14
+ * naked type param, but has the same contract as T.
15
+ *
16
+ * @note This must be used directly the condition itself: `NoDistribute<T> extends U`,
17
+ * it won't work wrapping a type argument passed to a conditional type.
18
+ *
19
+ * @see https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
20
+ */
21
+ export type NoDistribute < T > = T & { } ;
22
+
11
23
/**
12
24
* Mark a type as nullable (`null | undefined`).
13
25
* @param T type that will become nullable
Original file line number Diff line number Diff line change
1
+ import test from 'ava' ;
2
+ import { assert } from '../helpers/assert' ;
3
+
4
+ import { NoDistribute } from '../../src' ;
5
+
6
+ test ( "can create a conditional type that won't distribute over unions" , t => {
7
+ type IsString < T > = T extends string ? "Yes" : "No" ;
8
+ type IsStringNoDistribute < T > = NoDistribute < T > extends string ? "Yes" : "No" ;
9
+
10
+ /**
11
+ * Evaluates as:
12
+ * ("foo" extends string ? "Yes" : "No")
13
+ * | (42 extends string ? "Yes" : "No")
14
+ */
15
+ type T1 = IsString < "foo" | 42 > ;
16
+ assert < T1 , "Yes" | "No" > ( t ) ;
17
+ assert < "Yes" | "No" , T1 > ( t ) ;
18
+
19
+ /**
20
+ * Evaluates as:
21
+ * ("foo" | 42) extends string ? "Yes" : "No"
22
+ */
23
+ type T2 = IsStringNoDistribute < "foo" | 5 > ;
24
+ assert < T2 , "No" > ( t ) ;
25
+ assert < "No" , T2 > ( t ) ;
26
+ } ) ;
27
+
28
+ test ( "cannot be used to prevent a distributive conditional from distributing" , t => {
29
+ type IsString < T > = T extends string ? "Yes" : "No" ;
30
+ // It's the defintion of the conditional type that matters,
31
+ // not the type that's passed in, so this still distributes
32
+ type Test = IsString < NoDistribute < "foo" | 42 > > ;
33
+ assert < Test , "Yes" | "No" > ( t ) ;
34
+ assert < "Yes" | "No" , Test > ( t ) ;
35
+ } ) ;
You can’t perform that action at this time.
0 commit comments