Skip to content

Commit

Permalink
feat(micro-dash): remove dependency on the utility-types library
Browse files Browse the repository at this point in the history
  • Loading branch information
ersimont committed May 12, 2024
1 parent 059e0c5 commit e0d6a21
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 113 deletions.
13 changes: 2 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@angular/router": "^17.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"utility-types": "~3.10.0",
"zone.js": "~0.14.2"
},
"devDependencies": {
Expand Down
3 changes: 1 addition & 2 deletions projects/micro-dash/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
"lib": {
"entryFile": "src/public-api.ts",
"flatModuleFile": "micro-dash"
},
"allowedNonPeerDependencies": ["utility-types"]
}
}
2 changes: 1 addition & 1 deletion projects/micro-dash/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"url": "https://github.com/simontonsoftware/s-libs.git",
"directory": "projects/micro-dash"
},
"dependencies": { "tslib": "^2.3.0", "utility-types": "^3.10.0" },
"dependencies": { "tslib": "^2.3.0" },
"sideEffects": false
}
6 changes: 3 additions & 3 deletions projects/micro-dash/src/lib/array/compact.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Falsey } from 'utility-types';
import { Falsy } from '../interfaces';
import { identity } from '../util';

/**
Expand All @@ -8,7 +8,7 @@ import { identity } from '../util';
* - Lodash: 113 bytes
* - Micro-dash: 62 bytes
*/
export function compact<T>(array: readonly T[]): Array<Exclude<T, Falsey>> {
export function compact<T>(array: readonly T[]): Array<Exclude<T, Falsy>> {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- not sure why this rule triggers
return array.filter(identity) as Array<Exclude<T, Falsey>>;
return array.filter(identity) as Array<Exclude<T, Falsy>>;
}
15 changes: 13 additions & 2 deletions projects/micro-dash/src/lib/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// aliases
export type Nil = null | undefined;
export type Primitive = boolean | number | string;
export type Existent = Primitive | object;
export type Falsy = '' | 0 | false | null | undefined;
export type EmptyObject = Record<string, never>;
export type ObjectWith<T> = Record<string, T>;
export type StringifiedKey<T> = Cast<keyof T, string>;

// iteratees
export type ArrayIteratee<I, O> = (item: I, index: number) => O;
export type ArrayNarrowingIteratee<O> = (item: any, index: number) => item is O;
export type ObjectIteratee<T, O> = (
Expand All @@ -21,6 +23,7 @@ export type KeyNarrowingIteratee<I, O> = (
) => key is O;
export type ValueIteratee<T, O> = (value: T) => O;

// coercion
export type Cast<I, O> = Exclude<I, O> extends never ? I : O;
export type Narrow<I, O> = Extract<I, O> | Extract<O, I>;
export type IfCouldBe<T1, T2, If, Else = never> = Narrow<T1, T2> extends never
Expand All @@ -32,22 +35,30 @@ export type IfIndexType<T, If, Else = never> = string extends T
? If
: Else;

// object parts
type IndexKeys<T> = { [K in keyof T]: IfIndexType<K, K> }[keyof T];
type NonIndexKeys<T> = { [K in keyof T]: IfIndexType<K, never, K> }[keyof T];
export type PartialExceptIndexes<T> = {
[K in NonIndexKeys<T>]?: T[K];
} & { [K in IndexKeys<T>]: T[K] };

export type StringifiedKey<T> = Cast<keyof T, string>;
export type ValuesType<T> = T extends readonly []
? T[number]
: T extends ArrayLike<any>
? T[number]
: T extends object
? T[keyof T]
: never;
export type DeepPartial<T> = T extends Array<infer E>
? Array<DeepPartial<E>>
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T | undefined;

// misc
export type Evaluate<T> = T extends infer I ? { [K in keyof I]: T[K] } : never;

// very special-case
export type Drop1Arg<T extends Function> = T extends (
arg1: any,
...rest: infer A
Expand Down
5 changes: 2 additions & 3 deletions projects/micro-dash/src/lib/lang/is-match.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Falsey } from 'utility-types';
import { ObjectWith } from '../interfaces';
import { Falsy, ObjectWith } from '../interfaces';
import { isMatch } from './is-match';

describe('isMatch()', () => {
Expand Down Expand Up @@ -102,7 +101,7 @@ describe('isMatch()', () => {
});

it('should return `true` when comparing an empty `source`', () => {
const object = { a: 1 } as any[] | Falsey | { a: 1 };
const object = { a: 1 } as any[] | Falsy | { a: 1 };
expect(isMatch(object, [])).toBe(true);
expect(isMatch(object, {})).toBe(true);
expect(isMatch(object, null)).toBe(true);
Expand Down
2 changes: 1 addition & 1 deletion projects/micro-dash/src/lib/lang/is-match.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DeepPartial } from 'utility-types';
import { every } from '../collection/every';
import { DeepPartial } from '../interfaces';
import { isEmpty } from './is-empty';

/**
Expand Down
103 changes: 103 additions & 0 deletions projects/micro-dash/src/lib/object/invoke.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { staticTest } from '@s-libs/ng-dev';
import { expectTypeOf } from 'expect-type';
import { Nil } from '../interfaces';
import { invoke } from './invoke';

describe('invoke()', () => {
Expand All @@ -10,6 +13,106 @@ describe('invoke()', () => {
expect(spy.calls.first().object).toBe(obj);
});

it('has fancy typing', () => {
staticTest(() => {
//
// empty path
//

expectTypeOf(invoke({ a: () => 1 }, [])).toEqualTypeOf<undefined>();
expectTypeOf(
invoke({} as { a: () => string } | undefined, []),
).toEqualTypeOf<undefined>();

//
// 1 element path
//

expectTypeOf(invoke({ a: () => 1 }, ['a'])).toEqualTypeOf<number>();
expectTypeOf(
invoke({ a: (a: boolean) => a }, ['a'], true),
).toEqualTypeOf<boolean>();
expectTypeOf(invoke({} as { a?: () => string }, ['a'])).toEqualTypeOf<
string | undefined
>();
expectTypeOf(
invoke({} as Nil | { a: () => string }, ['a']),
).toEqualTypeOf<string | undefined>();

//
// 2 element path
//

expectTypeOf(
invoke({ a: { b: () => 1 } }, ['a', 'b']),
).toEqualTypeOf<number>();
expectTypeOf(
invoke({ a: { b: (a: boolean) => a } }, ['a', 'b'], true),
).toEqualTypeOf<boolean>();
expectTypeOf(
invoke({} as { a: { b?: () => string } }, ['a', 'b']),
).toEqualTypeOf<string | undefined>();
expectTypeOf(
invoke({} as { a?: { b: () => string } }, ['a', 'b']),
).toEqualTypeOf<string | undefined>();
expectTypeOf(
invoke({} as Nil | { a: { b: () => string } }, ['a', 'b']),
).toEqualTypeOf<string | undefined>();

//
// 3 element path
//

const path3: ['a', 'b', 'c'] = ['a', 'b', 'c'];
expectTypeOf(
invoke({ a: { b: { c: () => 1 } } }, path3),
).toEqualTypeOf<number>();
expectTypeOf(
invoke({ a: { b: { c: (a: boolean) => a } } }, path3, true),
).toEqualTypeOf<boolean>();
expectTypeOf(
invoke({} as { a: { b: { c?: () => string } } }, path3),
).toEqualTypeOf<string | undefined>();
expectTypeOf(
invoke({} as { a: { b?: { c: () => string } } }, path3),
).toEqualTypeOf<string | undefined>();
expectTypeOf(
invoke({} as { a?: { b: { c: () => string } } }, path3),
).toEqualTypeOf<string | undefined>();
expectTypeOf(
invoke({} as Nil | { a: { b: { c: () => string } } }, path3),
).toEqualTypeOf<string | undefined>();

// //
// // 4 element path
// //
//
// const path4: ["a", "b", "c", "d"] = ["a", "b", "c", "d"];
// // $ExpectType number
// invoke({ a: { b: { c: { d: () => 1 } } } }, path4);
// // $ExpectType boolean
// invoke({ a: { b: { c: { d: (a: boolean) => a } } } }, path4, true);
// // $ExpectType string | undefined
// invoke({} as { a: { b: { c: { d?: () => string } } } }, path4);
// // $ExpectType string | undefined
// invoke({} as { a: { b: { c?: { d: () => string } } } }, path4);
// // $ExpectType string | undefined
// invoke({} as { a: { b?: { c: { d: () => string } } } }, path4);
// // $ExpectType string | undefined
// invoke({} as { a?: { b: { c: { d: () => string } } } }, path4);
// // $ExpectType string | undefined
// invoke({} as { a: { b: { c: { d: () => string } } } } | Nil, path4);

//
// fallback: n element path
//

const pathN: string[] = ['a'];
// $ExpectType any
invoke({ a: () => 1 }, pathN);
});
});

//
// stolen from https://github.com/lodash/lodash
//
Expand Down
2 changes: 1 addition & 1 deletion projects/micro-dash/src/lib/object/invoke.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NonUndefined } from 'utility-types';
import { Existent, Nil } from '../interfaces';
import { isFunction } from '../lang';
import { get } from './get';

type Fn = (...args: any[]) => any;
type NonUndefined<T> = T extends undefined ? never : T;

type Obj1<K1 extends PropertyKey, V> = { [key in K1]?: V };
type Path1<
Expand Down
85 changes: 0 additions & 85 deletions projects/micro-dash/src/typing-tests/object/invoke.dts-spec.ts

This file was deleted.

3 changes: 3 additions & 0 deletions projects/ng-dev/src/lib/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type ResolveType<F> = F extends (...args: any[]) => Promise<infer U>
? U
: never;
6 changes: 3 additions & 3 deletions projects/ng-dev/src/lib/spies/test-call.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Deferred } from '@s-libs/js-core';
import { PromiseType } from 'utility-types';
import { AngularContext } from '../angular-context';
import { ResolveType } from '../interfaces';

/**
* A mock method call that was made and is ready to be answered. This interface allows access to the underlying <code>jasmine.CallInfo</code>, and allows resolving or rejecting the asynchronous call's result.
Expand All @@ -10,14 +10,14 @@ export class TestCall<F extends jasmine.Func> {
callInfo!: jasmine.CallInfo<F>;

constructor(
private deferred: Deferred<PromiseType<ReturnType<F>>>,
private deferred: Deferred<ResolveType<F>>,
private autoTick: boolean,
) {}

/**
* Resolve the call with the given value.
*/
flush(value: PromiseType<ReturnType<F>>): void {
flush(value: ResolveType<F>): void {
this.deferred.resolve(value);
this.maybeTick();
}
Expand Down

0 comments on commit e0d6a21

Please sign in to comment.