Skip to content

Commit

Permalink
fix(types): narrow return type of first and last (#160)
Browse files Browse the repository at this point in the history
Merged by gomerge CLI.
  • Loading branch information
crishoj authored Nov 10, 2024
1 parent b95cb73 commit 665ba72
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 10 deletions.
14 changes: 9 additions & 5 deletions src/array/first.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
* ```
* @version 12.1.0
*/
export function first<T>(array: readonly T[]): T | undefined

export function first<T, U>(array: readonly T[], defaultValue: U): T | U

export function first(array: readonly unknown[], defaultValue?: unknown) {
export function first<
const TArray extends readonly any[],
const TDefault = undefined,
>(
array: TArray,
defaultValue?: TDefault,
): TArray extends readonly [infer TFirst, ...any[]]
? TFirst
: TArray[number] | TDefault {
return array?.length > 0 ? array[0] : defaultValue
}
14 changes: 9 additions & 5 deletions src/array/last.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
* ```
* @version 12.1.0
*/
export function last<T>(array: readonly T[]): T | undefined

export function last<T, U>(array: readonly T[], defaultValue: U): T | U

export function last(array: readonly unknown[], defaultValue?: unknown) {
export function last<
const TArray extends readonly any[],
const TDefault = undefined,
>(
array: TArray,
defaultValue?: TDefault,
): TArray extends readonly [...any[], infer TLast]
? TLast
: TArray[number] | TDefault {
return array?.length > 0 ? array[array.length - 1] : defaultValue
}
40 changes: 40 additions & 0 deletions tests/array/first.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as _ from 'radashi'

describe('first', () => {
test('inlined array', () => {
expectTypeOf(_.first([])).toEqualTypeOf<undefined>()
expectTypeOf(_.first([1, 2, 3])).toEqualTypeOf<1>()
})

test('variable with empty array', () => {
const emptyArray = [] as never[]

expectTypeOf(_.first(emptyArray)).toEqualTypeOf<undefined>()
})

test('variable with mutable array', () => {
const array = [1, 2, 3]

expectTypeOf(_.first(array)).toEqualTypeOf<number | undefined>()
})

test('variable with readonly tuple', () => {
const emptyTuple = [] as const
const tuple = [1, 2, 3] as const

expectTypeOf(_.first(emptyTuple)).toEqualTypeOf<undefined>()
expectTypeOf(_.first(tuple)).toEqualTypeOf<1>()
})

test('with default value', () => {
const emptyArray = [] as never[]
const emptyTuple = [] as const
const array = [1, 2, 3]
const tuple = [1, 2, 3] as const

expectTypeOf(_.first(emptyArray, false)).toEqualTypeOf<false>()
expectTypeOf(_.first(emptyTuple, false)).toEqualTypeOf<false>()
expectTypeOf(_.first(array, false)).toEqualTypeOf<number | false>()
expectTypeOf(_.first(tuple, false)).toEqualTypeOf<1>()
})
})
40 changes: 40 additions & 0 deletions tests/array/last.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as _ from 'radashi'

describe('last', () => {
test('inlined array', () => {
expectTypeOf(_.last([])).toEqualTypeOf<undefined>()
expectTypeOf(_.last([1, 2, 3])).toEqualTypeOf<3>()
})

test('variable with empty array', () => {
const emptyArray = [] as never[]

expectTypeOf(_.last(emptyArray)).toEqualTypeOf<undefined>()
})

test('variable with mutable array', () => {
const array = [1, 2, 3]

expectTypeOf(_.last(array)).toEqualTypeOf<number | undefined>()
})

test('variable with readonly tuple', () => {
const emptyTuple = [] as const
const tuple = [1, 2, 3] as const

expectTypeOf(_.last(emptyTuple)).toEqualTypeOf<undefined>()
expectTypeOf(_.last(tuple)).toEqualTypeOf<3>()
})

test('with default value', () => {
const emptyArray = [] as never[]
const emptyTuple = [] as const
const array = [1, 2, 3]
const tuple = [1, 2, 3] as const

expectTypeOf(_.last(emptyArray, false)).toEqualTypeOf<false>()
expectTypeOf(_.last(emptyTuple, false)).toEqualTypeOf<false>()
expectTypeOf(_.last(array, false)).toEqualTypeOf<number | false>()
expectTypeOf(_.last(tuple, false)).toEqualTypeOf<3>()
})
})

0 comments on commit 665ba72

Please sign in to comment.