Hello, I'm not sure this is intended, but it destroys my solutions, as it doesn't follow a clear pattern. Not that I'm aware of in any case. I'm using a union type Record, followed by the tutorials of TypeScript's official documentation, but the minute I introduce conditional types into the mix, the record is simply split to multiple union Records, any thoughts on this would be appreciated.
TypeScript Version: 3.5.3
Search Terms: conditional types, union, null, record
Code
type RecordItems<Items extends string> = Record<Items, boolean>
type RecordItemsOrNull<Items extends string | null> = Items extends string ? Record<Items, boolean> : null
type RecordFruit = RecordItems<'orange' | 'apple' | 'banana'>
type RecordFruitOrNull = RecordItemsOrNull<'orange' | 'apple' | 'banana'>
const recordFruit: RecordFruit = {
orange: true
}
const recordFruitOrNull: RecordFruitOrNull = {
orange: true
}
Expected behavior:
Both the recordFruit and the recordFruitOrNull variables should break, since neither of them contain the entire record, the error should look like this:
test.ts:7:7 - error TS2739: Type '{ orange: true; }' is missing the following properties from type 'Record<"orange" | "apple" | "banana", boolean>': apple, banana
7 const recordFruit: RecordFruit = {
~~~~~~~~~~~
test.ts:10:7 - error TS2739: Type '{ orange: true; }' is missing the following properties from type 'Record<"orange" | "apple" | "banana", boolean>': apple, banana
10 const recordFruitOrNull: RecordFruitOrNull = {
~~~~~~~~~~~~~~~~~
Found 2 errors.
Actual behavior:
What actually happens is that the Record is split into union Records, e.g. Record<'orange', boolean> | Record<'apple', boolean> | Record<'banana', boolean> instead of following the regular pattern e.g. Record<'orange' | 'apple' | 'banana', boolean>
So there's only one error in my code sample, as the recordFruitOrNull variable passes:
test.ts:7:7 - error TS2739: Type '{ orange: true; }' is missing the following properties from type 'Record<"orange" | "apple" | "banana", boolean>': apple, banana
7 const recordFruit: RecordFruit = {
~~~~~~~~~~~
Found 1 error.
Playground Link:
Related Issues:
https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
To prevent the distributive behavior, define the type like:
type NonDist<T> = [T] extends [Whatever] ? ...
That makes sense, I must've missed that in the documentation. Thanks for your elegant example, this issue can now be closed.
Most helpful comment
https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
To prevent the distributive behavior, define the type like: