diff --git a/README.md b/README.md index 0d26a11..0efc0cd 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ Issues can be funded by anyone and the money will be transparently distributed t * [`Subtract`](#subtractt-t1) * [`Overwrite`](#overwritet-u) * [`Assign`](#assignt-u) +* [`ValuesType`](#valuestypet) ## Special operators @@ -586,6 +587,34 @@ type ExtendedProps = Assign; [⇧ back to top](#table-of-contents) +### `ValuesType` + +Get the union type of all the values in an object, tuple, array or array-like type `T`. + +**Usage:** + +```ts +import { ValuesType } from 'utility-types'; + +type Props = { name: string; age: number; visible: boolean }; +// Expect: string | number | boolean +type PropsValues = $ValuesType; + +type NumberArray = number[]; +// Expect: number +type NumberItems = $ValuesType; + +type ReadonlyNumberTuple = readonly [1, 2]; +// Expect: 1 | 2 +type AnotherNumberUnion = $ValuesType; + +type BinaryArray = Uint8Array; +// Expect: number +type BinaryItems = $ValuesType; +``` + +[⇧ back to top](#table-of-contents) + ### `Partial` Make all properties of object type optional diff --git a/src/__snapshots__/mapped-types.spec.ts.snap b/src/__snapshots__/mapped-types.spec.ts.snap index cae1971..c59ca75 100644 --- a/src/__snapshots__/mapped-types.spec.ts.snap +++ b/src/__snapshots__/mapped-types.spec.ts.snap @@ -182,4 +182,22 @@ exports[`SymmetricDifference testType>() 1`] = `"{ name: string; } | { age: number; } | { visible: boolean; }"`; +exports[`ValuesType testType>() 1`] = `"1 | 2"`; + +exports[`ValuesType testType>() 1`] = `"string | number | boolean"`; + +exports[`ValuesType testType>>() 1`] = `"string"`; + +exports[`ValuesType testType>() 1`] = `"number"`; + +exports[`ValuesType testType>() 1`] = `"number"`; + +exports[`ValuesType testType>() 1`] = `"number"`; + +exports[`ValuesType testType>() 1`] = `"number"`; + +exports[`ValuesType testType>() 1`] = `"1 | 2"`; + +exports[`ValuesType testType>() 1`] = `"symbol"`; + exports[`WritableKeys testType>() 1`] = `"\\"b\\""`; diff --git a/src/index.ts b/src/index.ts index 05dbbce..1881a3d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,7 @@ export { Subtract, SymmetricDifference, Unionize, + ValuesType, WritableKeys, } from './mapped-types'; diff --git a/src/mapped-types.spec.snap.ts b/src/mapped-types.spec.snap.ts index e9ca80c..caac4b0 100644 --- a/src/mapped-types.spec.snap.ts +++ b/src/mapped-types.spec.snap.ts @@ -39,6 +39,7 @@ import { PickByValueExact, OmitByValueExact, Optional, + ValuesType, } from './mapped-types'; /** @@ -501,3 +502,28 @@ type RequiredOptionalProps = { // @dts-jest:pass:snap -> Optional testType>({ name: 'Yolo', age: 99 }); } + +// @dts-jest:group ValuesType +{ + // @dts-jest:pass:snap -> string | number | boolean + testType>(); + + // @dts-jest:pass:snap -> number + testType>(); + // @dts-jest:pass:snap -> symbol + testType>(); + // @dts-jest:pass:snap -> string + testType>>(); + + // @dts-jest:pass:snap -> 1 | 2 + testType>(); + // @dts-jest:pass:snap -> 1 | 2 + testType>(); + + // @dts-jest:pass:snap -> number + testType>(); + // @dts-jest:pass:snap -> number + testType>(); + // @dts-jest:pass:snap -> number + testType>(); +} diff --git a/src/mapped-types.spec.ts b/src/mapped-types.spec.ts index eae4453..df2469d 100644 --- a/src/mapped-types.spec.ts +++ b/src/mapped-types.spec.ts @@ -39,6 +39,7 @@ import { PickByValueExact, OmitByValueExact, Optional, + ValuesType, } from './mapped-types'; /** @@ -501,3 +502,28 @@ type RequiredOptionalProps = { // @dts-jest:pass:snap testType>({ name: 'Yolo', age: 99 }); } + +// @dts-jest:group ValuesType +{ + // @dts-jest:pass:snap + testType>(); + + // @dts-jest:pass:snap + testType>(); + // @dts-jest:pass:snap + testType>(); + // @dts-jest:pass:snap + testType>>(); + + // @dts-jest:pass:snap + testType>(); + // @dts-jest:pass:snap + testType>(); + + // @dts-jest:pass:snap + testType>(); + // @dts-jest:pass:snap + testType>(); + // @dts-jest:pass:snap + testType>(); +} diff --git a/src/mapped-types.ts b/src/mapped-types.ts index 7bc928e..8dd318a 100644 --- a/src/mapped-types.ts +++ b/src/mapped-types.ts @@ -576,3 +576,41 @@ export type Optional = Omit< K > & Partial>; + +/** + * ValuesType + * @desc get the union type of all the values in an object, array or array-like type `T` + * @example + * type Props = { name: string; age: number; visible: boolean }; + * // Expect: string | number | boolean + * type PropsValues = ValuesType; + * + * type NumberArray = number[]; + * // Expect: number + * type NumberItems = ValuesType; + * + * type ReadonlySymbolArray = readonly symbol[]; + * // Expect: symbol + * type SymbolItems = ValuesType; + * + * type NumberTuple = [1, 2]; + * // Expect: 1 | 2 + * type NumberUnion = ValuesType; + * + * type ReadonlyNumberTuple = readonly [1, 2]; + * // Expect: 1 | 2 + * type AnotherNumberUnion = ValuesType; + * + * type BinaryArray = Uint8Array; + * // Expect: number + * type BinaryItems = ValuesType; + */ +export type ValuesType< + T extends ReadonlyArray | ArrayLike | Record +> = T extends ReadonlyArray + ? T[number] + : T extends ArrayLike + ? T[number] + : T extends object + ? T[keyof T] + : never;