Skip to content

Commit 7c2fecd

Browse files
committed
issue-#57, #43 - Re-instated use of 'Slice' type for some methods, deprecated 'Nameable' and 'TypeRef' related types, and added [pseudo] standalone (tsc) tests for 'Slice' type.
1 parent dff7723 commit 7c2fecd

File tree

11 files changed

+118
-37
lines changed

11 files changed

+118
-37
lines changed

packages/fjl/src/_platform/slice/index.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Methods that apply to the `Slice` Sum Type (e.g., intersection of `Array` and `String` types).
33
*/
4+
import {Slice} from "../../types";
5+
46
export const
57

68
/**
@@ -12,8 +14,8 @@ export const
1214
* method, itself, is actually exported from the library as `append`
1315
* (same as '+' for strings, but for concatables) See '../list/append' module.
1416
*/
15-
concat = (...xss: any[]): any =>
16-
xss.shift()?.concat(...xss),
17+
concat = <T extends Slice>(...xss: (T | ConcatArray<any>)[]): any =>
18+
xss.slice(0, 0).concat(...xss),
1719

1820
/**
1921
* Curried version of `concat`.
@@ -51,12 +53,12 @@ export const
5153
* Gets item at index; Same as` [].at()` (allows
5254
* negative/right-to-left indexing (see mdn `(Array|String).at` method).
5355
*/
54-
at = (i: number, xs: string | any[]) => xs.at(i),
56+
at = (i: number, xs: Slice) => xs.at(i),
5557

5658
/**
5759
* Curried version of `at`.
5860
*/
59-
$at = (i: number) => (xs: string | any[]) => xs.at(i)
61+
$at = (i: number) => (xs: Slice) => xs.at(i)
6062

6163
;
6264

packages/fjl/src/list/group.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import {groupBy} from "./groupBy";
22
import {equal} from "../boolean";
3+
import {Slice} from "../types";
34

45
/**
56
* The group function takes a list and returns a list of lists such that
67
* the concatenation of the result is equal to the argument. Moreover, each
78
* sublist in the result contains only equal elements. For example:
89
*
910
* ```javascript
10-
* group("Mississippi".slice(0)) === [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"],[ "i"]]
11+
* group("Mississippi".slice(0)) === [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], [ "i"]]
1112
* ```
1213
*/
13-
export const group = (xs: string | any[]): (string | any[])[] => groupBy(equal, xs);
14+
export const group = <T>(xs: Slice<T>): Slice<T>[] => groupBy(equal, xs);

packages/fjl/src/list/groupBy.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {BinaryPred} from "../types";
22
import {pushN} from "./pushN";
33
import {append} from "./append";
4+
import {Slice} from "../types";
45

56
export const
67

@@ -12,8 +13,8 @@ export const
1213
* [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], ["i"]]
1314
* ```
1415
*/
15-
groupBy = <X = string | any, XS extends string | X[] = X[]>(
16-
equalityOp: BinaryPred, xs: XS
16+
groupBy = <X = any, XS extends Slice<X> = Slice<X>>(
17+
equalityOp: BinaryPred<X, X>, xs: XS
1718
): XS[] => {
1819
if (!xs?.length) return [];
1920

@@ -52,7 +53,7 @@ export const
5253
/**
5354
* Curried version of `$groupBy`.
5455
*/
55-
$groupBy = <X = string | any, XS extends string | X[] = X[]>(
56+
$groupBy = <X = any, XS extends Slice<X> = Slice<X>>(
5657
equalityOp: BinaryPred
5758
) =>
5859
(xs: XS): XS[] =>

packages/fjl/src/list/inits.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {Slice} from "../types";
2+
13
export const
24
/**
35
* The inits function returns all initial segments of the argument (shortest first). For example:
@@ -6,7 +8,7 @@ export const
68
* shallowEquals(inits('abc'), ['','a','ab','abc'])
79
* ```
810
*/
9-
inits = (xs: string | any[]): (typeof xs)[] => {
11+
inits = (xs: Slice): (typeof xs)[] => {
1012
const limit = xs?.length,
1113
agg = [];
1214
if (!limit) return agg;

packages/fjl/src/list/last.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import {Slice} from "../types";
2+
13
/**
2-
* Returns last item of string, and/or, array..
4+
* @deprecated Use `at` instead.
5+
*
6+
* Returns last item of a slice.
37
*/
4-
export const last = (xs: string | any[]): string | any => xs.at(-1);
8+
export const last = <T = any, TS extends Slice<T> = Slice<T>>(xs: TS): T => xs.at(-1);

packages/fjl/src/list/mapAccumR.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import {MapAccumOp} from "../types";
1+
import {MapAccumOp, Slice} from "../types";
22

33
export const
44

55
/**
6-
* Performs a map and a reduce all in one (from right-to-left). Returns a tuple
7-
* containing the aggregated value and the result of mapping the passed in function on passed in list.
6+
* Takes a map reduce function and returns the result of the map (on each item) and the reducePerforms a map and a reduce all in one (from right-to-left) and returns the result of the reduce,
7+
* and the map as a tuple.
88
*/
99
mapAccumR = <A, B, C>(
1010
op: MapAccumOp<A, B, C>,
1111
zero: A,
12-
xs: string | B[]
13-
): [A, string | C[]] => {
12+
xs: Slice<B>
13+
): [A, Slice<C>] => {
1414
const limit = xs.length;
1515

16-
if (!limit) return [zero, xs.slice(0) as string | C[]];
16+
if (!limit) return [zero, xs.slice(0) as unknown as Slice<C>];
1717

1818
const mapped = [];
1919

@@ -28,7 +28,10 @@ export const
2828
return [agg, mapped];
2929
},
3030

31+
/**
32+
* Curried version of `mapAccumR`.
33+
*/
3134
$mapAccumR = <A, B, C>(op: MapAccumOp<A, B, C>) =>
3235
(zero: A) =>
33-
(xs: string | B[]): [A, string | C[]] =>
36+
(xs: Slice<B>): [A, Slice] =>
3437
mapAccumR(op, zero, xs);

packages/fjl/src/list/removeBy.ts

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export const
1919
return sliceCopy(list);
2020
},
2121

22+
/**
23+
* Curried version of `removeBy`.
24+
*/
2225
$removeBy = <T>(pred: BinaryPred<T>) =>
2326
(x: T) =>
2427
(list: Slice<T>): Slice<T> => removeBy(pred, x, list);
+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import {Slice} from "../../types";
2+
13
export const
24

35
/**
46
* Returns a copy of a slice (E.g., an array and/or a string).
57
*/
6-
sliceCopy = (xs: string | any[]): typeof xs => xs.slice(0)
8+
sliceCopy = (xs: Slice): typeof xs => xs.slice(0)
79

810
;

packages/fjl/src/types/data.ts

+24-17
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@
22
* General data types used in the library.
33
*/
44

5-
/**
6-
* Any type that contains a "readonly" `name` (functions, et al.) property.
7-
*/
8-
export interface Nameable {
9-
readonly name: string;
10-
}
11-
125
/**
136
* Represents strings, arrays, and/or, any structures that contain a `length`, and number indices.
147
*
@@ -19,23 +12,37 @@ export type NumberIndexable<T = unknown> = ({
1912
[index: number]: T;
2013
} |
2114
/**
22-
* Else support `string`.
15+
* Else support `string`, and other array types.
2316
*/
2417
{
2518
readonly length: number;
26-
readonly [index: number]: any; // Even though string variant type here
27-
// should actually be `string`, this is too strict for
28-
// a Sum type so `any` is used instead - this allows
29-
// `string`, and/or `Array` types, to be used where `NumberIndexable` type is required,
30-
// interchangeably.
19+
readonly [index: number]: any;
3120
});
3221

3322
/**
34-
* `Union + Sum` Slice type - Represents, the intersection, of the string,
35-
* array, and custom structure, types that match the `Slice` "summed" interfaces -
36-
* Basically a type for representing string, and/or "array structure" types.
23+
* The Slice type represents the intersection of string, array, and/or array-like, types.
24+
*/
25+
export interface Slice<T = any> extends Iterable<T> {
26+
readonly length: number;
27+
28+
[index: number]: any;
29+
30+
at(i: number): any; // @note Method not supported by older versions of typescript versions.
31+
concat(...items: (Slice<T> | ConcatArray<any>)[]): this;
32+
indexOf(x: any): number;
33+
includes(x: any): boolean;
34+
lastIndexOf(x: any): number;
35+
slice(start: number, end?: number): this;
36+
}
37+
38+
/**
39+
* @deprecated Use your own type and/or existing native/otherwise types.
40+
*
41+
* Any type that contains a "readonly" `name` (functions, et al.) property.
3742
*/
38-
export type Slice<T = any> = string | T[];
43+
export interface Nameable {
44+
readonly name: string;
45+
}
3946

4047
/**
4148
* @deprecated - Use direct type constructors instead.

packages/fjl/src/types/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,15 @@ export interface ConstructableType {
1212
// @todo clean this up and allow only one of these types
1313
export type Constructable = ConstructableType
1414
export type TypeConstructor = ConstructableType;
15+
16+
/**
17+
* @deprecated - Associated methods are deprecated, so these types are too -
18+
* Use `ConstructableType` types instead.
19+
*/
1520
export type TypeName = string;
21+
22+
/**
23+
* @deprecated - Associated methods are deprecated, so these types are too -
24+
* Use `ConstructableType` types instead.
25+
*/
1626
export type TypeRef = TypeName | ConstructableType;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* General ephemeral tests for `Slice` type - Tests just ensure that TSC (typescript compiler)
3+
* doesn't throw any errors when using the `Slice` type.
4+
*/
5+
import {Slice} from "../../src";
6+
7+
const {stringify} = JSON;
8+
9+
describe('Slice type', () => {
10+
it('Should be able to stand in for `string`, and `T[]` in function types', () => {
11+
const concat = <T extends Slice>(...xss: (T | ConcatArray<any>)[]): any =>
12+
xss[0].slice(0, 0).concat(...xss);
13+
14+
([
15+
[['abc', 'def'], 'abcdef'],
16+
['abcdef'.split('').map(x => [x]), 'abcdef']
17+
] as Slice[])
18+
.forEach(([args, expected]) => {
19+
it(`function context test: concat(${args.map((x: any) => stringify(x)).join(', ')}) === ${stringify(expected)}`, () => {
20+
const result: string = concat(...args); // Ensure return value is inferred to our inline declarations type,
21+
// e.g., no TSC error is thrown
22+
23+
expect(result).toEqual(expected);
24+
});
25+
});
26+
});
27+
28+
it('Should be able to stand in for `string`, and `T[]` types in standalone value declaration contexts;' +
29+
' e.g., it should not throw any TSC errors', () => {
30+
// Should be able to represent string values interchangeably (when calling `concat`, and/or `slice`, methods)
31+
const ctrlHead = 'all your base';
32+
const ctrlTail = 'belong to us';
33+
const someArray: Slice = ctrlHead.split(' ').map(x => x);
34+
35+
expect(ctrlHead.concat(ctrlTail)).toEqual(ctrlHead + ctrlTail);
36+
37+
expect(someArray.concat(...'all your base'.split(' ').map(xs => [xs]))).toEqual(['all', 'your', 'base']);
38+
39+
// Should ignore generic type param when value is a string; E.g., should not throw error
40+
// ----
41+
let someStr2: Slice<string> = 'hi';
42+
43+
someStr2 = ''.slice.call(someStr2, 0);
44+
expect(someStr2).toEqual('hi');
45+
});
46+
});

0 commit comments

Comments
 (0)