Created
September 22, 2019 22:13
-
-
Save karol-majewski/f0c0d1986add0b2a8b04cf9fe9506ed8 to your computer and use it in GitHub Desktop.
Homogeneous arrays in TypeScript (+ check if a type is a union)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Singleton = string; | |
type Union = string | number; | |
type DistributedKeyOf<T> = | |
T extends any | |
? keyof T | |
: never; | |
type DistributedValueOf<T> = T[DistributedKeyOf<T>]; | |
type IsSingleton<T> = | |
unknown extends DistributedValueOf<T> | |
? false | |
: true; | |
type T1 = IsSingleton<Singleton> // $ExpectType true | |
type T2 = IsSingleton<Union> // $ExpectType false | |
class HomogeneousArray<T> extends Array<IsSingleton<T> extends true ? T : never> {} | |
const numbers: HomogeneousArray<number> = [1, 2, 3]; // ✔ | |
const mixed: HomogeneousArray<string | number> = [1, '2', 3]; // ✘ |
Another solution based on the fact T | U
extends T & U
only when T
and U
are the same type.
/**
* @see https://stackoverflow.com/questions/53953814/typescript-check-if-a-type-is-a-union/53955431
*/
type IsSingleton<T> =
[T] extends [UnionToIntersection<T>]
? true
: false
type SingletonOnly<T> =
IsSingleton<T> extends true
? T
: never;
Great gist!
Was looking into homogeneous arrays and found shorter way to define it without checking for a union:
type HomogeneousArray<T extends unknown> = T extends unknown ? T[] : never
const a: HomogeneousArray<number | string> = [1, 2, '3'] // compile-time error
Nice! Your solution is simpler and gives a better error message, too.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
With circular type references (TypeScript 3.7)
we should be able to do:to have a compile-time error for a definition like
HomogeneousArray<string | number>
.