Skip to content

Commit 4d8638b

Browse files
committed
2 parents 9839961 + fceb147 commit 4d8638b

6 files changed

Lines changed: 306 additions & 103 deletions

File tree

types/clownface/clownface-tests.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Term, NamedNode, Dataset, Literal, DatasetCore, BlankNode, Quad_Graph,
22
import Clownface = require('clownface/lib/Clownface');
33
import clownface = require('clownface');
44
import Context = require('clownface/lib/Context');
5+
import filters = require('clownface/filter');
56

67
const node: NamedNode = <any> {};
78
const blankNode: BlankNode = <any> {};
@@ -237,6 +238,10 @@ function testFilter() {
237238
}
238239

239240
const multipleTypeGuarded: clownface.AnyPointer<NamedNode | BlankNode, Dataset> = anyPointer.filter<NamedNode | BlankNode>(onlyNamedOrBlank);
241+
242+
const fullSignature = mutliple.filter((ptr: clownface.GraphPointer<NamedNode>, index: number, pointers: Array<clownface.GraphPointer<NamedNode>>) => {
243+
return true;
244+
});
240245
}
241246

242247
function testForEach() {
@@ -454,3 +459,12 @@ function testAny() {
454459
anyPointer = multiPtr.any();
455460
anyPointer = graphPtr.any();
456461
}
462+
463+
function testFilterModule() {
464+
const { taggedLiteral } = filters;
465+
466+
const pointer: clownface.MultiPointer<Term, Dataset> = <any> {};
467+
468+
let literals: clownface.MultiPointer<Literal, Dataset> = pointer.filter(taggedLiteral('de'));
469+
literals = pointer.filter(taggedLiteral(['en-US', 'en']));
470+
}

types/clownface/filter.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Literal } from 'rdf-js';
2+
import { FilterCallback } from './';
3+
4+
declare function taggedLiteral(language: string | string[]): FilterCallback<any, any, Literal | Literal[]>;
5+
6+
declare const filters: {
7+
taggedLiteral: typeof taggedLiteral
8+
};
9+
10+
export = filters;

types/clownface/index.d.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Type definitions for clownface 1.2
22
// Project: https://github.com/rdf-ext/clownface
33
// Definitions by: tpluscode <https://github.com/tpluscode>
4+
// BenjaminHofstetter <https://github.com/BenjaminHofstetter>
45
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
56
// TypeScript Version: 3.4
67

@@ -43,6 +44,11 @@ declare namespace clownface {
4344
? Iteratee<T[0], D>
4445
: Iteratee<T, D>;
4546

47+
type ExtractContext<T extends AnyContext> = T extends undefined ? never : T extends any[] ? T[0] : T;
48+
49+
type FilterCallback<T extends AnyContext = AnyContext, D extends DatasetCore = DatasetCore, S extends T = T>
50+
= (ptr: Iteratee<T, D>, index: number, pointers: Array<GraphPointer<ExtractContext<T>>>) => ptr is Predicate<S, any>;
51+
4652
interface OutOptions {
4753
language?: string | string[] | undefined;
4854
}
@@ -58,9 +64,9 @@ declare namespace clownface {
5864
any(): AnyPointer<AnyContext, D>;
5965
list(): Iterable<Iteratee<T, D>> | null;
6066
isList(): boolean;
61-
toArray(): Array<AnyPointer<T extends undefined ? never : T extends any[] ? T[0] : T, D>>;
62-
filter<S extends T>(cb: (ptr: Iteratee<T, D>) => ptr is Predicate<S, any>): AnyPointer<S, D>;
63-
filter(cb: (ptr: Iteratee<T, D>) => boolean): AnyPointer<T, D>;
67+
toArray(): Array<AnyPointer<ExtractContext<T>, D>>;
68+
filter<S extends T>(cb: FilterCallback<T, D, S>): AnyPointer<S, D>;
69+
filter(cb: (ptr: Iteratee<T, D>, index: number, pointers: Array<GraphPointer<ExtractContext<T>>>) => boolean): AnyPointer<T, D>;
6470
forEach(cb: (quad: Iteratee<T, D>) => void): this;
6571
map<X>(cb: (quad: Iteratee<T, D>, index: number) => X): X[];
6672

types/ramda/index.d.ts

Lines changed: 24 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ import {
6969
ToTupleOfFunction,
7070
Tuple,
7171
CondPairTypeguard,
72+
Fn,
73+
IfFunctionsArgumentsDoNotOverlap,
74+
LargestArgumentsList,
7275
} from './tools';
7376

7477
export * from './tools';
@@ -807,78 +810,28 @@ export function contains<T>(a: T): (list: readonly T[]) => boolean;
807810
* are passed as arguments to the converging function to produce the return value.
808811
*/
809812
export function converge<
810-
TArgs extends any[],
811813
TResult,
812-
R1,
813-
R2,
814-
R3,
815-
R4,
816-
R5,
817-
R6,
818-
R7,
819-
RestFunctions extends Array<(...args: TArgs) => any>,
814+
FunctionsList extends ReadonlyArray<Fn> &
815+
IfFunctionsArgumentsDoNotOverlap<_Fns, 'Functions arguments types must overlap'>,
816+
_Fns extends ReadonlyArray<Fn> = FunctionsList,
820817
>(
821-
converging: (...args: [R1, R2, R3, R4, R5, R6, R7, ...ReturnTypesOfFns<RestFunctions>]) => TResult,
822-
branches: [
823-
(...args: TArgs) => R1,
824-
(...args: TArgs) => R2,
825-
(...args: TArgs) => R3,
826-
(...args: TArgs) => R4,
827-
(...args: TArgs) => R5,
828-
(...args: TArgs) => R6,
829-
(...args: TArgs) => R7,
830-
...RestFunctions,
831-
],
832-
): (...args: TArgs) => TResult;
833-
export function converge<TArgs extends any[], TResult, R1, R2, R3, R4, R5, R6, R7>(
834-
converging: (...args: [R1, R2, R3, R4, R5, R6, R7] & { length: 7 }) => TResult,
835-
branches: [
836-
(...args: TArgs) => R1,
837-
(...args: TArgs) => R2,
838-
(...args: TArgs) => R3,
839-
(...args: TArgs) => R4,
840-
(...args: TArgs) => R5,
841-
(...args: TArgs) => R6,
842-
(...args: TArgs) => R7,
843-
],
844-
): (...args: TArgs) => TResult;
845-
export function converge<TArgs extends any[], TResult, R1, R2, R3, R4, R5, R6>(
846-
converging: (...args: [R1, R2, R3, R4, R5, R6] & { length: 6 }) => TResult,
847-
branches: [
848-
(...args: TArgs) => R1,
849-
(...args: TArgs) => R2,
850-
(...args: TArgs) => R3,
851-
(...args: TArgs) => R4,
852-
(...args: TArgs) => R5,
853-
(...args: TArgs) => R6,
854-
],
855-
): (...args: TArgs) => TResult;
856-
export function converge<TArgs extends any[], TResult, R1, R2, R3, R4, R5>(
857-
converging: (...args: [R1, R2, R3, R4, R5] & { length: 5 }) => TResult,
858-
branches: [
859-
(...args: TArgs) => R1,
860-
(...args: TArgs) => R2,
861-
(...args: TArgs) => R3,
862-
(...args: TArgs) => R4,
863-
(...args: TArgs) => R5,
864-
],
865-
): (...args: TArgs) => TResult;
866-
export function converge<TArgs extends any[], TResult, R1, R2, R3, R4>(
867-
converging: (...args: [R1, R2, R3, R4] & { length: 4 }) => TResult,
868-
branches: [(...args: TArgs) => R1, (...args: TArgs) => R2, (...args: TArgs) => R3, (...args: TArgs) => R4],
869-
): (...args: TArgs) => TResult;
870-
export function converge<TArgs extends any[], TResult, R1, R2, R3>(
871-
converging: (...args: [R1, R2, R3] & { length: 3 }) => TResult,
872-
branches: [(...args: TArgs) => R1, (...args: TArgs) => R2, (...args: TArgs) => R3],
873-
): (...args: TArgs) => TResult;
874-
export function converge<TArgs extends any[], TResult, R1, R2>(
875-
converging: (...args: [R1, R2] & { length: 2 }) => TResult,
876-
branches: [(...args: TArgs) => R1, (...args: TArgs) => R2],
877-
): (...args: TArgs) => TResult;
878-
export function converge<TArgs extends any[], TResult, R1>(
879-
converging: (...args: [R1] & { length: 1 }) => TResult,
880-
branches: [(...args: TArgs) => R1],
881-
): (...args: TArgs) => TResult;
818+
converging: (...args: ReturnTypesOfFns<FunctionsList>) => TResult,
819+
branches: FunctionsList,
820+
): _.F.Curry<(...args: LargestArgumentsList<FunctionsList>) => TResult>;
821+
export function converge<
822+
CArgs extends ReadonlyArray<any>,
823+
TResult,
824+
FunctionsList extends readonly [
825+
...{
826+
[Index in keyof CArgs]: (...args: ReadonlyArray<any>) => CArgs[Index];
827+
},
828+
] &
829+
IfFunctionsArgumentsDoNotOverlap<_Fns, 'Functions arguments types must overlap'>,
830+
_Fns extends ReadonlyArray<Fn> = FunctionsList,
831+
>(
832+
converging: (...args: CArgs) => TResult,
833+
branches: FunctionsList,
834+
): _.F.Curry<(...args: LargestArgumentsList<FunctionsList>) => TResult>;
882835

883836
/**
884837
* Returns the number of items in a given `list` matching the predicate `f`
@@ -1054,9 +1007,7 @@ export function endsWith<T>(subList: readonly T[]): (list: readonly T[]) => bool
10541007
*/
10551008
export function eqBy<T>(fn: (a: T) => unknown, a: T, b: T): boolean;
10561009
export function eqBy<T>(fn: (a: T) => unknown, a: T): (b: T) => boolean;
1057-
export function eqBy<T>(
1058-
fn: (a: T) => unknown,
1059-
): {
1010+
export function eqBy<T>(fn: (a: T) => unknown): {
10601011
(a: T, b: T): boolean;
10611012
(a: T): (b: T) => boolean;
10621013
};

types/ramda/test/converge-tests.ts

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,22 @@ import * as R from 'ramda';
55
indent: number;
66
value: string;
77
}
8+
89
const indentN = R.pipe(R.times(R.always(' ')), R.join(''), R.replace(/^(?!$)/gm));
910

10-
// $ExpectType (args_0: FormatSpec) => string
11+
// $ExpectType Curry<(args_0: FormatSpec) => any>
1112
const format = R.converge(R.call, [({ indent }: FormatSpec) => indentN(indent), ({ value }: FormatSpec) => value]);
1213

1314
format({ indent: 2, value: 'foo\nbar\nbaz\n' }); // => ' foo\n bar\n baz\n'
15+
16+
// $ExpectType Curry<(args_0: FormatSpec) => string>
17+
const format2 = R.converge(R.call, [
18+
({ indent }: FormatSpec) => indentN(indent),
19+
({ value }: FormatSpec) => value,
20+
] as const);
21+
22+
// $ExpectType string
23+
const indented = format2({ indent: 2, value: 'foo\nbar\nbaz\n' }); // => ' foo\n bar\n baz\n'
1424
};
1525

1626
() => {
@@ -30,21 +40,20 @@ import * as R from 'ramda';
3040
return a + b;
3141
}
3242

33-
// ≅ multiply( add(1, 2), subtract(1, 2) );
34-
// $ExpectType (a: number, b: number) => number
43+
// $ExpectType Curry<(a: number, b: number) => number>
3544
const fn = R.converge(multiply, [add, subtract]);
3645

3746
// $ExpectError
38-
R.converge(concat, [add, subtract]);
47+
const fnMismatchedTypes = R.converge(concat, [add, subtract]);
3948

4049
// $ExpectError
4150
R.converge(multiply, [add, subtract, add]);
4251

4352
// $ExpectError
44-
R.converge(concat, []);
53+
const fnWrongNumberOfBranchesV1 = R.converge(concat, []);
4554

46-
// $ExpectError
47-
R.converge(() => {}, []);
55+
// $Expect Curry<() => void>
56+
const emptyFunction = R.converge(() => {}, []);
4857

4958
// $ExpectType number
5059
fn(1, 2);
@@ -70,7 +79,7 @@ import * as R from 'ramda';
7079
return a + b + c + d + e + f + g + h + i + j;
7180
}
7281

73-
// $ExpectType (a: number, b: number) => number
82+
// $ExpectType Curry<(a: number, b: number) => number>
7483
const fn10 = R.converge(add10, [
7584
multiply,
7685
add,
@@ -84,22 +93,69 @@ import * as R from 'ramda';
8493
multiply,
8594
]);
8695

87-
// TODO This should throw error, because the number of branches is not the same as converge arity
88-
const fnWrongNumberOfBranches = R.converge(add10, [
89-
multiply,
90-
add,
91-
subtract,
92-
multiply,
93-
add,
94-
subtract,
96+
const add3 = (a: number, b: number, c: number) => a + b + c;
97+
98+
// $ExpectError
99+
const fnWrongNumberOfBranches = R.converge(add3, [
100+
// Error because we have 4 branches, but expect 3 arguments (add3)
95101
multiply,
96102
add,
97103
subtract,
98104
multiply,
99-
add,
100-
subtract,
101105
]);
102106

103107
// $ExpectType number
104108
fn10(1, 2);
109+
110+
// because fifth function in branches has arity of 3 result function also must have largest arity
111+
// $ExpectType Curry<(a: number, b: number, c: number) => number>
112+
const fn10WithAdd3 = R.converge(add10, [add, add, add, add, add3, add, add, add, add, add]);
113+
114+
// $ExpectType number
115+
fn10WithAdd3(1, 2, 3);
116+
117+
const args1 = (a1: number | string) => 1;
118+
const args2 = (a1: number | bigint, a2: { q: string }) => 2;
119+
const args3 = (a1: number | symbol, a2: { w: number }, a3: number) => 3;
120+
121+
// resulted function must accept types of parameters that will satisfy every function in branches, so intersection must be used
122+
// $ExpectType Curry<(a1: number, a2: { w: number; } & { q: string; }, a3: number) => number>
123+
const intersectionOfArguments = R.converge(add3, [args1, args2, args3]);
124+
125+
// $ExpectType number
126+
const resultNumber = intersectionOfArguments(1, { q: 'text', w: 22 }, 11);
127+
128+
// $ExpectError
129+
const errorArguments = intersectionOfArguments(1, { q: 'text' }, 11);
130+
131+
const argsIncompatible = (a1: string) => 1;
132+
133+
// types: `string`, `number | symbol`, and `number | bigint` - do not have common type
134+
// $ExpectError
135+
const intersectionOfArgumentsIncompatible = R.converge(add3, [argsIncompatible, args2, args3]);
136+
137+
const addGeneric = <T>(a: T, b: T): T => b;
138+
139+
// need to use const if converging function is generic
140+
// $ExpectType Curry<(a: number, b: number) => number>
141+
const withGeneric0 = R.converge(addGeneric, [multiply, subtract] as const);
142+
143+
// unable to infer types correctly because generic `R.or` has overloads with different number of arguments
144+
// $ExpectType Curry<(a: number, b: number) => <U>(b: U) => unknown>
145+
const withGenericWrongInferred = R.converge(R.or, [add, subtract] as const);
146+
147+
// need to use wrapper `(...args) => convergingFunction(...args)` if converging function
148+
// is generic that has overloads with different number of arguments
149+
// $ExpectType Curry<(a: number, b: number, c: number) => number>
150+
const withGeneric1 = R.converge((...args) => R.or(...args), [add, add3] as const);
151+
152+
// or explicitly set type for converging function arguments
153+
// $ExpectType Curry<(a: number, b: number) => number>
154+
const withGeneric2 = R.converge((...args: [number, number]) => R.or(...args), [add, subtract]);
155+
156+
// $ExpectType Curry<(list: readonly number[] & ArrayLike<unknown>) => number>
157+
const getAverage = R.converge((...args) => R.divide(...args), [R.sum, R.length] as const);
158+
159+
// $ExpectType number
160+
const average = getAverage([1, 3, 0, 4]); // => 2
105161
};

0 commit comments

Comments
 (0)