From bb57638a351be9fcbbb81654e08680b727ec3305 Mon Sep 17 00:00:00 2001 From: Tommy Date: Sun, 14 Jul 2024 05:53:17 -0500 Subject: [PATCH] Add `NonEmptyTuple` type (#915) --- index.d.ts | 1 + readme.md | 1 + source/internal.d.ts | 5 ----- source/merge-deep.d.ts | 2 +- source/non-empty-tuple.d.ts | 21 +++++++++++++++++++++ test-d/non-empty-tuple.ts | 10 ++++++++++ 6 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 source/non-empty-tuple.d.ts create mode 100644 test-d/non-empty-tuple.ts diff --git a/index.d.ts b/index.d.ts index e04ba1ffe..e5d276115 100644 --- a/index.d.ts +++ b/index.d.ts @@ -130,6 +130,7 @@ export type {IsNull} from './source/is-null'; export type {IfNull} from './source/if-null'; export type {And} from './source/and'; export type {Or} from './source/or'; +export type {NonEmptyTuple} from './source/non-empty-tuple'; // Template literal types export type {CamelCase} from './source/camel-case'; diff --git a/readme.md b/readme.md index 14794a5d8..7abd6024e 100644 --- a/readme.md +++ b/readme.md @@ -202,6 +202,7 @@ Click the type names for complete docs. - [`DistributedPick`](source/distributed-pick.d.ts) - Picks keys from a type, distributing the operation over a union. - [`And`](source/and.d.ts) - Returns a boolean for whether two given types are both true. - [`Or`](source/or.d.ts) - Returns a boolean for whether either of two given types are true. +- [`NonEmptyTuple`](source/non-empty-tuple.d.ts) - Matches any non-empty tuple. ### Type Guard diff --git a/source/internal.d.ts b/source/internal.d.ts index f8a9f7c17..43b6cb733 100644 --- a/source/internal.d.ts +++ b/source/internal.d.ts @@ -251,11 +251,6 @@ Matches any unknown array or tuple. */ export type UnknownArrayOrTuple = readonly [...unknown[]]; -/** -Matches any non empty tuple. -*/ -export type NonEmptyTuple = readonly [unknown, ...unknown[]]; - /** Returns a boolean for whether the two given types extends the base type. */ diff --git a/source/merge-deep.d.ts b/source/merge-deep.d.ts index 1369748ae..a27037e2c 100644 --- a/source/merge-deep.d.ts +++ b/source/merge-deep.d.ts @@ -5,9 +5,9 @@ import type {Merge} from './merge'; import type { FirstArrayElement, IsBothExtends, - NonEmptyTuple, UnknownArrayOrTuple, } from './internal'; +import type {NonEmptyTuple} from './non-empty-tuple'; import type {ArrayTail} from './array-tail'; import type {UnknownRecord} from './unknown-record'; import type {EnforceOptional} from './enforce-optional'; diff --git a/source/non-empty-tuple.d.ts b/source/non-empty-tuple.d.ts new file mode 100644 index 000000000..a11251a21 --- /dev/null +++ b/source/non-empty-tuple.d.ts @@ -0,0 +1,21 @@ +/** +Matches any non-empty tuple. + +@example +``` +import type {NonEmptyTuple} from 'type-fest'; + +const sum = (...numbers: NonEmptyTuple) => numbers.reduce((total, value) => total + value, 0); + +sum(1, 2, 3); +//=> 6 + +sum(); +//=> Error: Expected at least 1 arguments, but got 0. +``` + +@see {@link RequireAtLeastOne} for objects + +@category Array +*/ +export type NonEmptyTuple = readonly [T, ...T[]]; diff --git a/test-d/non-empty-tuple.ts b/test-d/non-empty-tuple.ts new file mode 100644 index 000000000..880f4cc8e --- /dev/null +++ b/test-d/non-empty-tuple.ts @@ -0,0 +1,10 @@ +import {expectType} from 'tsd'; +import type {NonEmptyTuple} from '../index'; + +declare const sum: (...numbers: NonEmptyTuple) => number; + +expectType(sum(1, 2, 3)); +expectType(sum(1)); + +// @ts-expect-error +sum();