Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ export type {IsUppercase} from './source/is-uppercase.d.ts';
export type {IsOptional} from './source/is-optional.d.ts';
export type {IsNullable} from './source/is-nullable.d.ts';
export type {TupleOf} from './source/tuple-of.d.ts';
export type {IndexOf} from './source/index-of.d.ts';
export type {LastIndexOf} from './source/last-index-of.d.ts';
export type {IndicesOf} from './source/indices-of.d.ts';

// Template literal types
export type {CamelCase, CamelCaseOptions} from './source/camel-case.d.ts';
Expand Down
64 changes: 64 additions & 0 deletions source/index-of.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type {GreaterThanOrEqual} from './greater-than-or-equal.d.ts';
import type {ApplyDefaultOptions} from './internal/object.d.ts';
import type {IsOptionalKeyOf} from './is-optional-key-of.d.ts';
import type {ReverseSign} from './internal/numeric.d.ts';
import type {UnknownArray} from './unknown-array.d.ts';
import type {IsAnyOrNever} from './internal/type.d.ts';
import type {LiteralUnion} from './literal-union.d.ts';
import type {IsEqual} from './is-equal.d.ts';

/* eslint-disable type-fest/require-exported-types */
export type Inc<T extends number[]> = [...T, 1];
export type Neg<T extends number[]> = ReverseSign<T['length']>;
export type IndexOfOptions = {
ignoreOptionalModifier?: boolean;
fromIndex?: number;
};
/* eslint-enable type-fest/require-exported-types */

type DefaultIndexOfOptions = {
ignoreOptionalModifier: false;
fromIndex: 0;
};

export type IndexOf<
Array_ extends UnknownArray, Item,
Options extends IndexOfOptions = {},
> = IsAnyOrNever<Array_> extends true ? Array_
: _IndexOf<Array_, Item,
ApplyDefaultOptions<
IndexOfOptions,
DefaultIndexOfOptions,
Options
>
>;

type _IndexOf<
Array_ extends UnknownArray, Item,
Options extends Required<IndexOfOptions>,
F_Index extends number[] = [],
B_Index extends number[] = [1],
T_Index extends number[] = never,
> =
keyof Array_ & `${number}` extends never
// Backward search
? Array_ extends readonly [...infer Rest, infer Last]
? IsEqual<Last, Item> extends true
? _IndexOf<Rest, Item, Options, F_Index, Inc<B_Index>, B_Index>
: _IndexOf<Rest, Item, Options, F_Index, Inc<B_Index>, T_Index>
: Array_ extends readonly [] ? Neg<T_Index>
: IsEqual<Array_[number], Item> extends false ? Neg<T_Index>
: LiteralUnion<F_Index, number>
// Forward search
: Array_ extends readonly [(infer First)?, ...infer Rest]
? GreaterThanOrEqual<F_Index['length'], Options['fromIndex']> extends true
? IsEqual<First, Item> extends true ? F_Index['length'] | (
Options['ignoreOptionalModifier'] extends true ? never
: IsOptionalKeyOf<Array_, '0'> extends false ? never
: _IndexOf<Rest, Item, Options, Inc<F_Index>>)
: _IndexOf<Rest, Item, Options, Inc<F_Index>>
: _IndexOf<Rest, Item, Options, Inc<F_Index>>

: never;

export {};
66 changes: 66 additions & 0 deletions source/indices-of.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type {ApplyDefaultOptions} from './internal/object.d.ts';
import type {IsOptionalKeyOf} from './is-optional-key-of.d.ts';
import type {UnknownArray} from './unknown-array.d.ts';
import type {IsAnyOrNever} from './internal/type.d.ts';
import type {Inc, Neg} from './index-of.d.ts';
import type {IsEqual} from './is-equal.d.ts';

type IndicesOfOptions = {
ignoreOptionalModifier?: boolean;
// FromIndex?: number;
};

type DefaultIndicesOfOptions = {
ignoreOptionalModifier: false;
// FromIndex: 0;
};

export type IndicesOf<
Array_ extends UnknownArray, Item,
Options extends IndicesOfOptions = {},
> = IsAnyOrNever<Array_> extends true ? Array_
: _IndicesOf<Array_, Item,
ApplyDefaultOptions<
IndicesOfOptions,
DefaultIndicesOfOptions,
Options
>
>;

type _IndicesOf<
Array_ extends UnknownArray, Item,
Options extends Required<IndicesOfOptions>,
F_Index extends number[] = [],
F_Indices extends Array<number | undefined> = [],
B_Index extends number[] = [1],
B_Indices extends Array<number | undefined> = [],
T_Index extends number = F_Index['length'],
> =
keyof Array_ & `${number}` extends never

? Array_ extends readonly [...infer Rest, infer Last]
? IsEqual<Last, Item> extends true
? _IndicesOf<Rest, Item, Options, F_Index, F_Indices, Inc<B_Index>, [Neg<B_Index>, ...B_Indices]>
: _IndicesOf<Rest, Item, Options, F_Index, F_Indices, Inc<B_Index>, B_Indices>

: [
...F_Indices,
...Array_ extends readonly [] ? []
: IsEqual<Array_[number], Item> extends false ? []
: [Array_[number] | (number & {})],
...B_Indices,
]

: Array_ extends readonly [(infer First)?, ...infer Rest]
? IsEqual<First, Item> extends true
? _IndicesOf<Rest, Item, Options, Inc<F_Index>, [
...F_Indices,
...Options['ignoreOptionalModifier'] extends true ? [T_Index]
: IsOptionalKeyOf<Array_, '0'> extends false ? [T_Index]
: [T_Index?],
]>
: _IndicesOf<Rest, Item, Options, Inc<F_Index>, F_Indices>

: never;

export {};
74 changes: 74 additions & 0 deletions source/last-index-of.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type {GreaterThanOrEqual} from './greater-than-or-equal.d.ts';
import type {ApplyDefaultOptions} from './internal/object.d.ts';
import type {IsOptionalKeyOf} from './is-optional-key-of.d.ts';
import type {Inc, Neg, IndexOfOptions} from './index-of.d.ts';
import type {UnknownArray} from './unknown-array.d.ts';
import type {IsAnyOrNever} from './internal/type.d.ts';
import type {LiteralUnion} from './literal-union.d.ts';
import type {GreaterThan} from './greater-than.d.ts';
import type {IsEqual} from './is-equal.d.ts';

type DefaultLastIndexOfOptions = {
ignoreOptionalModifier: false;
fromIndex: 0;
};

type IsLastOptional<T extends UnknownArray> =
T extends [...infer Rest, (infer _)?]
? [...Rest] extends T
? true
: false
: false;

export type LastIndexOf<
Array_ extends UnknownArray, Item,
Options extends IndexOfOptions = {},
> = IsAnyOrNever<Array_> extends true ? Array_
: _LastIndexOf<Array_, Item,
ApplyDefaultOptions<
IndexOfOptions,
DefaultLastIndexOfOptions,
Options
>
>;

type _LastIndexOf<
Array_ extends UnknownArray, Item,
Options extends Required<IndexOfOptions>,
F_Index extends number[] = [],
B_Index extends number[] = [1],
T_Index extends number = never,
> =
number extends Array_['length']
? keyof Array_ & `${number}` extends never

? Array_ extends readonly [...infer Rest, infer Last]
? GreaterThan<B_Index['length'], Options['fromIndex']> extends true
? IsEqual<Last, Item> extends true ? Neg<B_Index>
: _LastIndexOf<Rest, Item, Options, F_Index, Inc<B_Index>, T_Index>
: _LastIndexOf<Rest, Item, Options, F_Index, Inc<B_Index>, T_Index>

: Array_ extends readonly [] ? T_Index
: IsEqual<Array_[number], Item> extends false ? T_Index
: LiteralUnion<F_Index['length'], number>

: Array_ extends readonly [(infer First)?, ...infer Rest]
? IsEqual<First, Item> extends true
? _LastIndexOf<Rest, Item, Options, Inc<F_Index>, B_Index, F_Index['length'] | (
Options['ignoreOptionalModifier'] extends true ? never
: IsOptionalKeyOf<Array_, '0'> extends false ? never
: _LastIndexOf<Rest, Item, Options, Inc<F_Index>, B_Index, T_Index>)>
: _LastIndexOf<Rest, Item, Options, Inc<F_Index>, B_Index, T_Index>
: never

: Array_ extends readonly [...infer Rest, (infer Last)?]
? GreaterThanOrEqual<F_Index['length'], Options['fromIndex']> extends true
? IsEqual<Last, Item> extends true ? Required<Rest>['length'] | (
Options['ignoreOptionalModifier'] extends true ? never
: IsLastOptional<Array_> extends false ? never
: _LastIndexOf<Rest, Item, Options, Inc<F_Index>>)
: _LastIndexOf<Rest, Item, Options, Inc<F_Index>>
: _LastIndexOf<Rest, Item, Options, Inc<F_Index>>
: never;

export {};