From b0ac4fa20191a5b454ac221623dd31b3aceedb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levi=20=28Nguy=E1=BB=85n=20L=C6=B0=C6=A1ng=20Huy=29?= Date: Sat, 18 Feb 2023 16:39:38 +0700 Subject: [PATCH] feat(useArrayFindLast): new function (#2471) --- packages/shared/useArrayFindLast/index.md | 31 ++++++++++++++ .../shared/useArrayFindLast/index.test.ts | 37 +++++++++++++++++ packages/shared/useArrayFindLast/index.ts | 40 +++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 packages/shared/useArrayFindLast/index.md create mode 100644 packages/shared/useArrayFindLast/index.test.ts create mode 100644 packages/shared/useArrayFindLast/index.ts diff --git a/packages/shared/useArrayFindLast/index.md b/packages/shared/useArrayFindLast/index.md new file mode 100644 index 00000000000..b0584a41c2a --- /dev/null +++ b/packages/shared/useArrayFindLast/index.md @@ -0,0 +1,31 @@ +--- +category: Array +--- + +# useArrayFindLast + +Reactive `Array.findLast`. + +## Usage + +```js +import { useArrayFindLast } from '@vueuse/core' + +const list = [ref(1), ref(-1), ref(2)] +const positive = useArrayFindLast(list, val => val > 0) +// positive.value: 2 +``` + +### Use with reactive array + +```js +import { useArrayFindLast } from '@vueuse/core' + +const list = reactive([-1, -2]) +const positive = useArrayFindLast(list, val => val > 0) +// positive.value: undefined +list.push(10) +// positive.value: 10 +list.push(5) +// positive.value: 5 +``` diff --git a/packages/shared/useArrayFindLast/index.test.ts b/packages/shared/useArrayFindLast/index.test.ts new file mode 100644 index 00000000000..63bf18fd4c5 --- /dev/null +++ b/packages/shared/useArrayFindLast/index.test.ts @@ -0,0 +1,37 @@ +import { reactive, ref } from 'vue-demi' +import { useSetup } from '../../.test' +import { useArrayFindLast } from '../useArrayFindLast' + +describe('useArrayFindLast', () => { + it('should be defined', () => { + expect(useArrayFindLast).toBeDefined() + }) + + it('should find positive', () => { + useSetup(() => { + const item1 = ref(1) + const item2 = ref(2) + const item3 = ref(3) + const positive = useArrayFindLast([item1, item2, item3], val => val > 0) + expect(positive.value).toBe(3) + item3.value = -1 + expect(positive.value).toBe(2) + item2.value = -1 + expect(positive.value).toBe(1) + item1.value = -1 + expect(positive.value).toBe(undefined) + }) + }) + + it('should work with reactive array', () => { + useSetup(() => { + const list = reactive([-1, -2]) + const positive = useArrayFindLast(list, val => val > 0) + expect(positive.value).toBe(undefined) + list.push(10) + expect(positive.value).toBe(10) + list.push(5) + expect(positive.value).toBe(5) + }) + }) +}) diff --git a/packages/shared/useArrayFindLast/index.ts b/packages/shared/useArrayFindLast/index.ts new file mode 100644 index 00000000000..18e0d5b105b --- /dev/null +++ b/packages/shared/useArrayFindLast/index.ts @@ -0,0 +1,40 @@ +import type { ComputedRef } from 'vue-demi' +import { computed } from 'vue-demi' +import type { MaybeComputedRef } from '../utils' +import { resolveUnref } from '../resolveUnref' + +// Polyfill for node version < 18 +function findLast(arr: T[], cb: (element: T, index: number, array: T[]) => boolean): T | undefined { + let index = arr.length + while (index-- > 0) { + if (cb(arr[index], index, arr)) + return arr[index] + } + return undefined +} + +/** + * Reactive `Array.findLast` + * + * @see https://vueuse.org/useArrayFindLast + * @param {Array} list - the array was called upon. + * @param fn - a function to test each element. + * + * @returns the last element in the array that satisfies the provided testing function. Otherwise, undefined is returned. + */ +export function useArrayFindLast( + list: MaybeComputedRef[]>, + fn: (element: T, index: number, array: MaybeComputedRef[]) => boolean, +): ComputedRef { + return computed(() => + resolveUnref( + // @ts-expect-error - missing in types + // https://github.com/microsoft/TypeScript/issues/48829 + !Array.prototype.findLast + ? findLast(resolveUnref(list), (element, index, array) => fn(resolveUnref(element), index, array)) + : resolveUnref(list) + // @ts-expect-error - missing in types + .findLast((element, index, array) => fn(resolveUnref(element), index, array)), + ), + ) +}