From ed088ba063dba471c5c2f22f824d360f4ebbf450 Mon Sep 17 00:00:00 2001 From: TomokiMiyauci Date: Fri, 2 Jul 2021 19:58:10 +0900 Subject: [PATCH] :bug: Improve type inference --- common/init.ts | 87 ++++++++++++++++++++++++ test/init.test.ts => common/init_test.ts | 14 +++- common/mod.ts | 2 + deps.ts | 3 +- dev_deps.ts | 4 ++ mod.ts | 1 - src/init.ts | 36 ---------- test/init.ts | 40 ----------- 8 files changed, 107 insertions(+), 80 deletions(-) create mode 100644 common/init.ts rename test/init.test.ts => common/init_test.ts (65%) delete mode 100644 src/init.ts delete mode 100644 test/init.ts diff --git a/common/init.ts b/common/init.ts new file mode 100644 index 00000000..0e744e0f --- /dev/null +++ b/common/init.ts @@ -0,0 +1,87 @@ +// Copyright 2021-present the Fonction authors. All rights reserved. MIT license. +import { slice } from '../deps.ts' + +/** + * @example + * ```ts + * InitString // string + * InitString<''> // '' + * InitString<'a'> // '' + * InitString<'ab'> // 'a' + * InitString<'abcd'> // 'abc' + * ``` + * @internal + */ +type InitString = T extends `${infer F}${infer R}` + ? R extends '' + ? '' + : `${F}${InitString}` + : T extends '' + ? '' + : string + +/** + * Infer the init types. + * @typeParam T - `string` or any `array` + * + * @example + * ```ts + * // String + * Init // string + * Init<''> // '' + * Init<'hello'> // 'hell' + * ``` + * + * @example + * ```ts + * // Array + * Init<[] | never[] | readonly [] | readonly never[]> // [] + * Init<['hello', 'world']> // 'hello' + * ``` + * + * @category `Array` `String` + * + * @see Related to {@link First} + * + * @public + */ +type Init = T extends string + ? InitString + : T extends readonly never[] | [] + ? [] + : T extends readonly [...infer I, unknown] + ? I + : T + +/** + * Returns all but the init element of the given list or string. + * @param val - string or any array object + * @returns The result of `val.slice(0, -1)` + * + * @example + * ```ts + * // String + * init('hello') // 'hell' + * init('h') // '' + * init('') // '' + * ``` + * + * @example + * ```ts + * init([1, 2, 3]) // [1, 2] + * init(['hello', 'world']) // ['hello'] + * init(['hello']) // [] + * init([]) // [] + * ``` + * + * @category `Array` `String` + * + * @see Related to {@link tail} + * + * @public + */ +const init = (val: T): Init => + slice(0, -1, val) as Init + +export { init } +export type { Init } diff --git a/test/init.test.ts b/common/init_test.ts similarity index 65% rename from test/init.test.ts rename to common/init_test.ts index 403005d6..8a50219e 100644 --- a/test/init.test.ts +++ b/common/init_test.ts @@ -1,6 +1,6 @@ // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. -import { assertEquals } from '../dev_deps.ts' -import { init } from '../src/init.ts' +import { assertEquals, assertEqualsType } from '../dev_deps.ts' +import { Init, init } from './init.ts' Deno.test('init', () => { const tableString: [string, string][] = [ @@ -37,4 +37,14 @@ Deno.test('init', () => { tableArray.forEach(([val, expected]) => { assertEquals(init(val), expected, `init(${val}) -> ${expected}`) }) + + assertEqualsType<[], Init<[]>>() + assertEqualsType>() + assertEqualsType<[], Init<[1]>>() + assertEqualsType<[1], Init<[1, 2]>>() + assertEqualsType<[1, 2], Init<[1, 2, 3]>>() + assertEqualsType<'', Init<''>>() + assertEqualsType<'', Init<'a'>>() + assertEqualsType<'a', Init<'ab'>>() + assertEqualsType<'abcde', Init<'abcdef'>>() }) diff --git a/common/mod.ts b/common/mod.ts index 01fb8937..1e045173 100644 --- a/common/mod.ts +++ b/common/mod.ts @@ -1,5 +1,7 @@ // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. export type { Head } from './head.ts' export { head } from './head.ts' +export type { Init } from './init.ts' +export { init } from './init.ts' export type { Last } from './last.ts' export { last } from './last.ts' diff --git a/deps.ts b/deps.ts index 0c91cd64..a1656a07 100644 --- a/deps.ts +++ b/deps.ts @@ -1,5 +1,6 @@ // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. -export { length } from 'https://deno.land/x/core_fn@v1.0.0-beta.8/mod.ts' +export { length } from 'https://deno.land/x/core_fn@v1.0.0-beta.14/mod.ts' +export { slice } from 'https://deno.land/x/core_fn@v1.0.0-beta.14/uncurry/common/slice.ts' export { curry } from 'https://deno.land/x/curry@v1.0.0/mod.ts' export { equal } from 'https://deno.land/x/equal@v1.5.0/mod.ts' export { diff --git a/dev_deps.ts b/dev_deps.ts index 838ee9b4..eaf5e206 100644 --- a/dev_deps.ts +++ b/dev_deps.ts @@ -1,8 +1,12 @@ // Copyright 2021-present the Fonction authors. All rights reserved. MIT license. +/* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/no-unused-vars */ + export { assert, assertEquals } from 'https://deno.land/std@0.97.0/testing/asserts.ts' +export const assertEqualsType = (_actual?: U): void => {} export { length } from 'https://deno.land/x/core_fn@v1.0.0-beta.8/mod.ts' export { isNumber, diff --git a/mod.ts b/mod.ts index 0957174b..c489bad3 100644 --- a/mod.ts +++ b/mod.ts @@ -22,7 +22,6 @@ export { identity } from './src/identity.ts' export { ifElse } from './src/ifElse.ts' export { ifElseFn } from './src/ifElseFn.ts' export { inc } from './src/inc.ts' -export { init } from './src/init.ts' export { K } from './src/K.ts' export { lt } from './src/lt.ts' export { lte } from './src/lte.ts' diff --git a/src/init.ts b/src/init.ts deleted file mode 100644 index 5594c33d..00000000 --- a/src/init.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021-present the Fonction authors. All rights reserved. MIT license. -/** - * Returns all but the last element of the given list or string. - * - * @param val - string or any array object - * @returns The result of `val.slice(0, -1)` - * - * @example - * ```ts - * // String - * init('hello') // 'hell' - * init('h') // '' - * init('') // '' - * ``` - * - * @example - * ```ts - * init([1, 2, 3]) // [1, 2] - * init(['hello', 'world']) // ['hello'] - * init(['hello']) // [] - * init([]) // [] - * ``` - * - * @category `Array` `String` - * - * @see Related to {@link tail} - * - * @public - */ -const init: { - (val: string): string - (val: T): T - // eslint-disable-next-line @typescript-eslint/no-explicit-any -} = (val: any) => val.slice(0, -1) - -export { init } diff --git a/test/init.ts b/test/init.ts deleted file mode 100644 index 403005d6..00000000 --- a/test/init.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2021-present the Fonction authors. All rights reserved. MIT license. -import { assertEquals } from '../dev_deps.ts' -import { init } from '../src/init.ts' - -Deno.test('init', () => { - const tableString: [string, string][] = [ - ['', ''], - ['a', ''], - ['ab', 'a'], - ['abc', 'ab'] - ] - tableString.forEach(([val, expected]) => { - assertEquals(init(val), expected, `init(${val}) -> ${expected}`) - }) - - const tableArray: [unknown[], unknown[]][] = [ - [[], []], - [[''], []], - [[undefined], []], - [[null], []], - [[0], []], - [['', ''], ['']], - [[0, 0], [0]], - [[0, ''], [0]], - [['hello', 'world'], ['hello']], - [ - ['hello', 'new', 'world'], - ['hello', 'new'] - ], - [ - [undefined, null, 'hello', 'world'], - [undefined, null, 'hello'] - ], - [[['hello', 'world']], []] - ] - - tableArray.forEach(([val, expected]) => { - assertEquals(init(val), expected, `init(${val}) -> ${expected}`) - }) -})