From c3334b000173cb1e8a40d2ac50328292ad99965f Mon Sep 17 00:00:00 2001 From: Dejan Toteff Date: Thu, 23 Jan 2025 19:22:45 +0200 Subject: [PATCH] chore@small --- files/index.d.ts | 158 ++++++++++++++++++++++++++++- package.json | 1 - source/pipe-spec.ts | 231 ++++++++++++++++++++++++++++++------------- source/piped-spec.ts | 189 +++++------------------------------ 4 files changed, 344 insertions(+), 235 deletions(-) diff --git a/files/index.d.ts b/files/index.d.ts index 31d31a23..02c06929 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -3357,7 +3357,7 @@ Notes: */ // @SINGLE_MARKER -export function pipe( +export function pipe( ...funcs: [ f1: (...args: TArgs) => R1, f2: (a: R1) => R2, @@ -3371,10 +3371,166 @@ export function pipe R10, f11: (a: R10) => R11, f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16, + f17: (a: R16) => R17, + f18: (a: R17) => R18, + f19: (a: R18) => R19, + f20: (a: R19) => R20, ...func: Array<(a: any) => any>, fnLast: (a: any) => TResult ] ): (...args: TArgs) => TResult; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16, + f17: (a: R16) => R17, + f18: (a: R17) => R18, + f19: (a: R18) => R19, + f20: (a: R19) => R20 +): (...args: TArgs) => R20; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16, + f17: (a: R16) => R17, + f18: (a: R17) => R18, + f19: (a: R18) => R19 +): (...args: TArgs) => R19; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16, + f17: (a: R16) => R17, + f18: (a: R17) => R18 +): (...args: TArgs) => R18; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16, + f17: (a: R16) => R17 +): (...args: TArgs) => R17; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15, + f16: (a: R15) => R16 +): (...args: TArgs) => R16; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14, + f15: (a: R14) => R15 +): (...args: TArgs) => R15; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13, + f14: (a: R13) => R14 +): (...args: TArgs) => R14; +export function pipe( + f1: (...args: TArgs) => R1, + f2: (a: R1) => R2, + f3: (a: R2) => R3, + f4: (a: R3) => R4, + f5: (a: R4) => R5, + f6: (a: R5) => R6, + f7: (a: R6) => R7, + f8: (a: R7) => R8, + f9: (a: R8) => R9, + f10: (a: R9) => R10, + f11: (a: R10) => R11, + f12: (a: R11) => R12, + f13: (a: R12) => R13 +): (...args: TArgs) => R13; export function pipe( f1: (...args: TArgs) => R1, f2: (a: R1) => R2, diff --git a/package.json b/package.json index 7674f6a6..f1b28a22 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "test:ci": "jest source/*.spec.js --coverage --no-cache -w 1", "test:typings": "dtslint --localTs ./node_modules/typescript/lib --expectOnly ./source", "create-docsify": "cd ../rambda-scripts && yarn create-docsify", - "pipe": "jest source/pipe.spec.js > pipe.log", "ts": "yarn test:typings" }, "depFn": [ diff --git a/source/pipe-spec.ts b/source/pipe-spec.ts index 42aa4a37..c863943a 100644 --- a/source/pipe-spec.ts +++ b/source/pipe-spec.ts @@ -1,80 +1,179 @@ import { - add, - subtract, - pipe, - map, - filter, - identity, - dissoc, - inc, - negate, -} from 'rambda' + add, + allPass, + anyPass, + append, + assoc, + assocPath, + both, + defaultTo, + difference, + dissocPath, + dropLast, + either, + filter, + head, + inc, + map, + negate, + pipe, + tap, +} from 'rambda'; -interface Input { - a: string, - b: string, +type IsNotNever = [T] extends [never] ? false : true; +type Expect = T; + +interface BaseBook { + title: string; + year: number; + description?: string; + userRating?: number; +} +interface Book extends BaseBook { + awards: { + number: number; + years?: number[]; + }; + status?: Status; +} +interface MustReadBook extends Book { + status: 'must-read'; +} +interface FamousBook extends Book { + status: 'famous'; +} +interface BookWithBookmarkStatus extends Book { + bookmarkFlag: boolean; +} +interface BookWithReadStatus extends Book { + readFlag: boolean; +} +type BookToRead = BookWithBookmarkStatus & BookWithReadStatus; +interface BookWithDescription extends Book { + description: string; } -interface Output { - c: string, +interface BookWithUserRating extends Book { + userRating: number; } +type BookWithDetails = BookWithDescription & BookWithUserRating; -describe('R.pipe with explicit types', () => { - it('with explicit types - complex', () => { - const obj = { - a: 'foo', - b: 'bar', - } - interface AfterInput { - a: number, - } - interface BeforeOutput { - b: string, - } +const zaratustra: BaseBook = { + title: 'Zaratustra', + year: 1956, +}; +const awardedZaratustra: Book = { + ...zaratustra, + awards: { + number: 1, + years: [1956], + }, +}; +const awardedDostojevski: Book = { + title: 'Idiot', + year: 1869, + awards: { + number: 2, + years: [1869, 1870], + }, +}; +const awardedDostojevskiToRead: BookToRead = { + ...awardedDostojevski, + readFlag: true, + bookmarkFlag: true, +}; +const awardedZaratustraToRead: BookToRead = { + ...awardedZaratustra, + readFlag: true, + bookmarkFlag: true, +}; +const awardedBaseValue: Book = { + title: '', + year: 0, + awards: { + number: 0, + years: [], + }, +}; - const result = pipe( - x => ({a: x.a.length + x.b.length}), - x => ({b: x.a + 'foo'}), - x => ({c: x.b + 'bar'}) - )(obj) +type Status = 'famous' | 'can be skipped' | 'must-read'; - result // $ExpectType Output - }) - it('with explicit types - correct', () => { - const obj = { - a: 'foo', - b: 'bar', - } +function checkIfMustRead(x: Book): x is MustReadBook { + return (x as MustReadBook).status === 'must-read'; +} +function checkIfFamous(x: Book): x is FamousBook { + return (x as FamousBook).status === 'famous'; +} +function checkReadStatus(x: Book): x is BookWithReadStatus { + return (x as BookWithReadStatus).readFlag; +} +function checkBookmarkStatus(x: Book): x is BookWithBookmarkStatus { + return (x as BookWithBookmarkStatus).bookmarkFlag; +} +function checkBookToRead(x: Book): x is BookToRead { + return (x as BookToRead).readFlag && (x as BookToRead).bookmarkFlag; +} +function checkHasDescription(x: Book): x is BookWithDescription { + return (x as BookWithDescription).description !== undefined; +} +function checkHasUserRating(x: Book): x is BookWithUserRating { + return (x as BookWithUserRating).userRating !== undefined; +} - const result = pipe(input => { - input // $ExpectType Input - return input as unknown as Output - }, identity)(obj) - result // $ExpectType Output - }) - it('with explicit types - wrong', () => { - const obj: Input = { - a: 'foo', - b: 'bar', - } +function assertType(fn: (x: T) => x is U) { + return (x: T) => { + if (fn(x)) { + return x; + } + throw new Error('type assertion failed'); + }; +} +function convertToType() { + return (x: U) => x as unknown as T; +} - // @ts-expect-error - pipe(identity, dissoc('b'))(obj) - }) -}) +// function mergeType(x: T){ +// return x as MergeType +// } + +describe('real use cases', () => { + it('books', () => { + const result = pipe( + assoc('status', 'famous' as Status), + assocPath('awards.number', 1), + defaultTo(awardedBaseValue), + tap(anyPass([(x) => x.awards.number > 1, (x) => x.year > 1900])), + tap( + both( + (x) => x.awards.number > 1, + (x) => x.year > 1900, + ), + ), + assertType(either(checkIfFamous, checkIfMustRead)), + assertType(both(checkReadStatus, checkBookmarkStatus)), + // // mergeType, + assertType(checkBookToRead), + (x) => [x], + dropLast(1), + difference([awardedDostojevskiToRead]), + append(awardedZaratustraToRead), + head, + assertType(allPass([checkHasDescription, checkHasUserRating])), + tap((x) => { + x; // $ExpectType BookWithDescription & BookWithUserRating + }), + assertType(anyPass([checkHasDescription, checkHasUserRating])), + convertToType(), + dissocPath('description'), + )( + zaratustra, + ) + const final: Expect> = true; + final; // $ExpectType true + }); +}); -describe('R.pipe', () => { - it('happy', () => { - const result = pipe(subtract(11), add(1), add(1))(1) - result // $ExpectType number - }) - it('happy - more complex', () => { - const result = pipe( - (x: string) => x.length + 1, - (x: number) => x + 1 - )('foo') - result // $ExpectType number - }) +describe('R.pipe', () => { it('with R.filter', () => { const result = pipe( filter(x => x > 2), diff --git a/source/piped-spec.ts b/source/piped-spec.ts index b5fb6c5a..4d4dd36a 100644 --- a/source/piped-spec.ts +++ b/source/piped-spec.ts @@ -1,167 +1,22 @@ -import { - allPass, - anyPass, - append, - assoc, - assocPath, - both, - defaultTo, - difference, - dissocPath, - dropLast, - either, - head, - piped, - tap, -} from 'rambda'; - -type IsNotNever = [T] extends [never] ? false : true; -type Expect = T; - -interface BaseBook { - title: string; - year: number; - description?: string; - userRating?: number; -} -interface Book extends BaseBook { - awards: { - number: number; - years?: number[]; - }; - status?: Status; -} -interface MustReadBook extends Book { - status: 'must-read'; -} -interface FamousBook extends Book { - status: 'famous'; -} -interface BookWithBookmarkStatus extends Book { - bookmarkFlag: boolean; -} -interface BookWithReadStatus extends Book { - readFlag: boolean; -} -type BookToRead = BookWithBookmarkStatus & BookWithReadStatus; -interface BookWithDescription extends Book { - description: string; -} -interface BookWithUserRating extends Book { - userRating: number; -} -type BookWithDetails = BookWithDescription & BookWithUserRating; - -const zaratustra: BaseBook = { - title: 'Zaratustra', - year: 1956, -}; -const awardedZaratustra: Book = { - ...zaratustra, - awards: { - number: 1, - years: [1956], - }, -}; -const awardedDostojevski: Book = { - title: 'Idiot', - year: 1869, - awards: { - number: 2, - years: [1869, 1870], - }, -}; -const awardedDostojevskiToRead: BookToRead = { - ...awardedDostojevski, - readFlag: true, - bookmarkFlag: true, -}; -const awardedZaratustraToRead: BookToRead = { - ...awardedZaratustra, - readFlag: true, - bookmarkFlag: true, -}; -const awardedBaseValue: Book = { - title: '', - year: 0, - awards: { - number: 0, - years: [], - }, -}; - -type Status = 'famous' | 'can be skipped' | 'must-read'; - -function checkIfMustRead(x: Book): x is MustReadBook { - return (x as MustReadBook).status === 'must-read'; -} -function checkIfFamous(x: Book): x is FamousBook { - return (x as FamousBook).status === 'famous'; -} -function checkReadStatus(x: Book): x is BookWithReadStatus { - return (x as BookWithReadStatus).readFlag; -} -function checkBookmarkStatus(x: Book): x is BookWithBookmarkStatus { - return (x as BookWithBookmarkStatus).bookmarkFlag; -} -function checkBookToRead(x: Book): x is BookToRead { - return (x as BookToRead).readFlag && (x as BookToRead).bookmarkFlag; -} -function checkHasDescription(x: Book): x is BookWithDescription { - return (x as BookWithDescription).description !== undefined; -} -function checkHasUserRating(x: Book): x is BookWithUserRating { - return (x as BookWithUserRating).userRating !== undefined; -} - -function assertType(fn: (x: T) => x is U) { - return (x: T) => { - if (fn(x)) { - return x; - } - throw new Error('type assertion failed'); - }; -} -function convertToType() { - return (x: U) => x as unknown as T; -} - -// function mergeType(x: T){ -// return x as MergeType -// } - -describe('real use cases', () => { - it('books', () => { - const result = piped( - zaratustra, - assoc('status', 'famous' as Status), - assocPath('awards.number', 1), - defaultTo(awardedBaseValue), - tap(anyPass([(x) => x.awards.number > 1, (x) => x.year > 1900])), - tap( - both( - (x) => x.awards.number > 1, - (x) => x.year > 1900, - ), - ), - assertType(either(checkIfFamous, checkIfMustRead)), - assertType(both(checkReadStatus, checkBookmarkStatus)), - // // mergeType, - assertType(checkBookToRead), - (x) => [x], - dropLast(1), - difference([awardedDostojevskiToRead]), - append(awardedZaratustraToRead), - head, - assertType(allPass([checkHasDescription, checkHasUserRating])), - tap((x) => { - x; // $ExpectType BookWithDescription & BookWithUserRating - }), - assertType(anyPass([checkHasDescription, checkHasUserRating])), - convertToType(), - dissocPath('description'), - ); - const final: Expect> = true; - final; // $ExpectType true - }); -}); +import {piped} from 'rambda' + +describe('R.piped', () => { + it('happy', () => { + const result = piped( + [1, 2], + x => { + return x.length + 1 + }, + x => { + return x + 10 + } + ) + + result // $ExpectType number + }) + it('issue #63', () => { + const result = piped(1, x => x) + + result // $ExpectType number + }) +})