inferred-types 0.37.0 → 0.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2745 -0
- package/dist/index.js +854 -0
- package/package.json +6 -12
- package/.eslintrc +0 -77
- package/.github/workflows/main.yml +0 -34
- package/.github/workflows/other.yml +0 -15
- package/.nvmrc +0 -1
- package/.prettierrc.js +0 -3
- package/.vscode/launch.json +0 -27
- package/.vscode/settings.json +0 -19
- package/devops/build.js +0 -243
- package/docs/builder-overview.md +0 -45
- package/docs/builder.md +0 -94
- package/src/errors/ReadOnlyViolation.ts +0 -3
- package/src/errors/index.ts +0 -12
- package/src/index.ts +0 -14
- package/src/runtime/README.md +0 -3
- package/src/runtime/api/api.ts +0 -10
- package/src/runtime/api/index.ts +0 -12
- package/src/runtime/builders/Model.ts +0 -25
- package/src/runtime/builders/url.ts +0 -15
- package/src/runtime/combinators/and.ts +0 -15
- package/src/runtime/combinators/filter.ts +0 -267
- package/src/runtime/combinators/index.ts +0 -4
- package/src/runtime/combinators/not.ts +0 -15
- package/src/runtime/combinators/or.ts +0 -5
- package/src/runtime/createFnWithProps.ts +0 -37
- package/src/runtime/dictionary/arrayToKeyLookup.ts +0 -19
- package/src/runtime/dictionary/defineProperties.ts +0 -35
- package/src/runtime/dictionary/dictArr.ts +0 -69
- package/src/runtime/dictionary/dictionaryTransform.ts +0 -22
- package/src/runtime/dictionary/entries.ts +0 -33
- package/src/runtime/dictionary/index.ts +0 -21
- package/src/runtime/dictionary/kv/dictToKv.ts +0 -21
- package/src/runtime/dictionary/kv/filterDictArray.ts +0 -31
- package/src/runtime/dictionary/kv/index.ts +0 -15
- package/src/runtime/dictionary/kv/kv.ts +0 -18
- package/src/runtime/dictionary/kv/kvToDict.ts +0 -24
- package/src/runtime/dictionary/mapTo.ts +0 -206
- package/src/runtime/dictionary/mapValues.ts +0 -23
- package/src/runtime/dictionary/merge.ts +0 -36
- package/src/runtime/dictionary/strArrayToDict.ts +0 -12
- package/src/runtime/index.ts +0 -23
- package/src/runtime/keys.ts +0 -16
- package/src/runtime/lists/asArray.ts +0 -38
- package/src/runtime/lists/createConverter.ts +0 -62
- package/src/runtime/lists/groupBy.ts +0 -15
- package/src/runtime/lists/index.ts +0 -15
- package/src/runtime/literals/ExplicitFunction.ts +0 -10
- package/src/runtime/literals/Suggest.ts +0 -19
- package/src/runtime/literals/arrayToObject.ts +0 -78
- package/src/runtime/literals/box.ts +0 -98
- package/src/runtime/literals/defineType.ts +0 -20
- package/src/runtime/literals/ensureLeading.ts +0 -17
- package/src/runtime/literals/ensureTrailing.ts +0 -17
- package/src/runtime/literals/identity.ts +0 -12
- package/src/runtime/literals/index.ts +0 -23
- package/src/runtime/literals/literal.ts +0 -48
- package/src/runtime/literals/pathJoin.ts +0 -33
- package/src/runtime/literals/stripLeading.ts +0 -15
- package/src/runtime/literals/stripTrailing.ts +0 -15
- package/src/runtime/literals/wide.ts +0 -13
- package/src/runtime/ruleset.ts +0 -42
- package/src/runtime/runtime/README.md +0 -3
- package/src/runtime/runtime/condition.ts +0 -13
- package/src/runtime/runtime/index.ts +0 -16
- package/src/runtime/runtime/type.ts +0 -127
- package/src/runtime/runtime/withValue.ts +0 -39
- package/src/runtime/state/Configurator.ts +0 -76
- package/src/runtime/state/FluentConfigurator.ts +0 -49
- package/src/runtime/state/index.ts +0 -13
- package/src/runtime/type-checks/ifSameType.ts +0 -20
- package/src/runtime/type-checks/ifTypeOf.ts +0 -124
- package/src/runtime/type-checks/index.ts +0 -24
- package/src/runtime/type-checks/isArray.ts +0 -34
- package/src/runtime/type-checks/isBoolean.ts +0 -24
- package/src/runtime/type-checks/isFalse.ts +0 -29
- package/src/runtime/type-checks/isFunction.ts +0 -26
- package/src/runtime/type-checks/isNull.ts +0 -26
- package/src/runtime/type-checks/isNumber.ts +0 -20
- package/src/runtime/type-checks/isObject.ts +0 -22
- package/src/runtime/type-checks/isString.ts +0 -34
- package/src/runtime/type-checks/isSymbol.ts +0 -3
- package/src/runtime/type-checks/isTrue.ts +0 -31
- package/src/runtime/type-checks/isUndefined.ts +0 -33
- package/src/runtime/type-checks/startsWith.ts +0 -107
- package/src/runtime/valueTypes.ts +0 -48
- package/src/types/Api.ts +0 -16
- package/src/types/Constructor.ts +0 -5
- package/src/types/EnumValues.ts +0 -14
- package/src/types/ExpandRecursively.ts +0 -12
- package/src/types/FunctionType.ts +0 -19
- package/src/types/If.ts +0 -10
- package/src/types/Include.ts +0 -18
- package/src/types/KeyedRecord.ts +0 -21
- package/src/types/Keys.ts +0 -26
- package/src/types/Length.ts +0 -8
- package/src/types/Mutable.ts +0 -8
- package/src/types/Narrowable.ts +0 -5
- package/src/types/Not.ts +0 -13
- package/src/types/Numeric.ts +0 -20
- package/src/types/Opaque.ts +0 -11
- package/src/types/README.md +0 -3
- package/src/types/Retain.ts +0 -16
- package/src/types/SimplifyObject.ts +0 -12
- package/src/types/Transformer.ts +0 -15
- package/src/types/TypeGuard.ts +0 -7
- package/src/types/Where.ts +0 -40
- package/src/types/alphabetic/AllCaps.ts +0 -15
- package/src/types/alphabetic/CamelCase.ts +0 -3
- package/src/types/alphabetic/CapFirstAlpha.ts +0 -23
- package/src/types/alphabetic/CapitalizeWords.ts +0 -9
- package/src/types/alphabetic/Cardinality.ts +0 -80
- package/src/types/alphabetic/DashToSnake.ts +0 -3
- package/src/types/alphabetic/DashUppercase.ts +0 -19
- package/src/types/alphabetic/Dasherize.ts +0 -23
- package/src/types/alphabetic/EnsureLeading.ts +0 -24
- package/src/types/alphabetic/EnsureTrailing.ts +0 -24
- package/src/types/alphabetic/HasUppercase.ts +0 -16
- package/src/types/alphabetic/IsCapitalized.ts +0 -18
- package/src/types/alphabetic/KebabCase.ts +0 -13
- package/src/types/alphabetic/LowerAllCaps.ts +0 -5
- package/src/types/alphabetic/PascalCase.ts +0 -29
- package/src/types/alphabetic/PathJoin.ts +0 -54
- package/src/types/alphabetic/Pluralize.ts +0 -112
- package/src/types/alphabetic/SnakeCase.ts +0 -27
- package/src/types/alphabetic/StripLeading.ts +0 -23
- package/src/types/alphabetic/StripTrailing.ts +0 -23
- package/src/types/alphabetic/Url.ts +0 -29
- package/src/types/alphabetic/alpha-characters.ts +0 -81
- package/src/types/alphabetic/index.ts +0 -32
- package/src/types/append-types.ts +0 -10
- package/src/types/boolean-logic/EndsWith.ts +0 -40
- package/src/types/boolean-logic/Extends.ts +0 -22
- package/src/types/boolean-logic/HasParameters.ts +0 -21
- package/src/types/boolean-logic/Includes.ts +0 -33
- package/src/types/boolean-logic/IsLiteral.ts +0 -101
- package/src/types/boolean-logic/IsScalar.ts +0 -20
- package/src/types/boolean-logic/IsUndefined.ts +0 -20
- package/src/types/boolean-logic/Or.ts +0 -12
- package/src/types/boolean-logic/StartsWith.ts +0 -42
- package/src/types/boolean-logic/TypeDefault.ts +0 -58
- package/src/types/boolean-logic/array.ts +0 -57
- package/src/types/boolean-logic/boolean.ts +0 -84
- package/src/types/boolean-logic/equivalency.ts +0 -15
- package/src/types/boolean-logic/index.ts +0 -14
- package/src/types/boolean-logic/object.ts +0 -30
- package/src/types/boolean-logic/string.ts +0 -21
- package/src/types/dictionary/DictChangeValue.ts +0 -34
- package/src/types/dictionary/DictPartialApplication.ts +0 -30
- package/src/types/dictionary/DictPrependWithFn.ts +0 -23
- package/src/types/dictionary/DictReturnValues.ts +0 -27
- package/src/types/dictionary/Get.ts +0 -14
- package/src/types/dictionary/MapTo.ts +0 -428
- package/src/types/dictionary/MutableProps.ts +0 -19
- package/src/types/dictionary/RequireProps.ts +0 -15
- package/src/types/dictionary/SameKeys.ts +0 -11
- package/src/types/dictionary/index.ts +0 -21
- package/src/types/dictionary/props.ts +0 -145
- package/src/types/fluent/fluent.ts +0 -61
- package/src/types/fluent/index.ts +0 -12
- package/src/types/functions/FinalReturn.ts +0 -12
- package/src/types/functions/LogicFunction.ts +0 -4
- package/src/types/functions/index.ts +0 -13
- package/src/types/index.ts +0 -49
- package/src/types/kv/DictFromKv.ts +0 -3
- package/src/types/kv/KeyValue.ts +0 -12
- package/src/types/kv/KvFrom.ts +0 -8
- package/src/types/kv/KvTuple.ts +0 -14
- package/src/types/kv/index.ts +0 -15
- package/src/types/lists/AfterFirst.ts +0 -10
- package/src/types/lists/ConvertAndMap.ts +0 -152
- package/src/types/lists/FilterTuple.ts +0 -20
- package/src/types/lists/First.ts +0 -8
- package/src/types/lists/FirstString.ts +0 -4
- package/src/types/lists/Split.ts +0 -21
- package/src/types/lists/UniqueForProp.ts +0 -18
- package/src/types/lists/index.ts +0 -18
- package/src/types/literal-unions/OptRequired.ts +0 -4
- package/src/types/literal-unions/index.ts +0 -1
- package/src/types/maybe.ts +0 -9
- package/src/types/ruleset-types.ts +0 -76
- package/src/types/runtime.ts +0 -39
- package/src/types/string-literals/Break.ts +0 -22
- package/src/types/string-literals/Concat.ts +0 -9
- package/src/types/string-literals/LeftWhitespace.ts +0 -13
- package/src/types/string-literals/Replace.ts +0 -17
- package/src/types/string-literals/RightWhitespace.ts +0 -13
- package/src/types/string-literals/StringLength.ts +0 -34
- package/src/types/string-literals/Trim.ts +0 -15
- package/src/types/string-literals/TrimLeft.ts +0 -14
- package/src/types/string-literals/TrimRight.ts +0 -14
- package/src/types/string-literals/form-fields.ts +0 -15
- package/src/types/string-literals/index.ts +0 -21
- package/src/types/tuples/DictArray.ts +0 -21
- package/src/types/tuples/FirstKey.ts +0 -10
- package/src/types/tuples/FirstKeyValue.ts +0 -9
- package/src/types/tuples/FirstOfEach.ts +0 -13
- package/src/types/tuples/FromDictArray.ts +0 -14
- package/src/types/tuples/SecondOfEach.ts +0 -13
- package/src/types/tuples/index.ts +0 -17
- package/src/types/type-conversion/TupleToUnion.ts +0 -9
- package/src/types/type-conversion/UnionToIntersection.ts +0 -9
- package/src/types/type-conversion/UnionToTuple.ts +0 -20
- package/src/types/type-conversion/Widen.ts +0 -22
- package/src/types/type-conversion/index.ts +0 -16
- package/src/types/type-testing.ts +0 -14
- package/tests/CamelCase-spec.ts +0 -20
- package/tests/Configurator-spec.hold +0 -106
- package/tests/ExplicitFunction-spec.ts +0 -50
- package/tests/IncludeAndRetain-spec.ts +0 -67
- package/tests/Includes-spec.ts +0 -36
- package/tests/KebabCase-spec.ts +0 -21
- package/tests/PascalCase-spec.ts +0 -22
- package/tests/Pluralize-spec.ts +0 -23
- package/tests/SnakeCase-spec.ts +0 -21
- package/tests/Where.spec.ts +0 -38
- package/tests/arrayToKeyLookup-spec.ts +0 -17
- package/tests/arrayToObject-spec.ts +0 -115
- package/tests/boolean-logic/Contains.test.ts +0 -55
- package/tests/boolean-logic/HasParameters.ts +0 -29
- package/tests/boolean-logic/IsLiteral.spec.ts +0 -65
- package/tests/boolean-logic/boolean.spec.ts +0 -21
- package/tests/boolean-logic/filter.spec.ts +0 -52
- package/tests/constructor.spec.ts +0 -42
- package/tests/createFnWithProps.spec.ts +0 -14
- package/tests/data/SimpleTable.hold +0 -21
- package/tests/data/index.ts +0 -12
- package/tests/data/playlist.hold +0 -25
- package/tests/data/song.hold +0 -23
- package/tests/defineType-spec.ts +0 -57
- package/tests/dictionary/DictChangeValue.test.ts +0 -30
- package/tests/dictionary/DictPartialApplication.test.ts +0 -43
- package/tests/dictionary/DictReturnValues.test.ts +0 -36
- package/tests/dictionary/Get.spec.ts +0 -28
- package/tests/dictionary/IntersectingKeys.test.ts +0 -42
- package/tests/dictionary/MutableProps.test.ts +0 -30
- package/tests/dictionary/OptionalKeys.test.ts +0 -24
- package/tests/dictionary/PrependValuesWithFunction.test.ts +0 -34
- package/tests/dictionary/RequireProps.test.ts +0 -21
- package/tests/dictionary/RequiredKeys.test.ts +0 -53
- package/tests/dictionary/TypeDefault.test.ts +0 -76
- package/tests/dictionary/mapTo.test.ts +0 -388
- package/tests/dictionary/merge.test.ts +0 -41
- package/tests/dictionaryTransform-spec.ts +0 -280
- package/tests/ifTypeOf-spec.ts +0 -191
- package/tests/kv/KeyValue-spec.ts +0 -22
- package/tests/kv/SameKeys-spec.ts +0 -35
- package/tests/kv/dict-to-kv-and-back.spec.ts +0 -169
- package/tests/kv/entries-spec.ts +0 -65
- package/tests/kv/keys.spec.ts +0 -66
- package/tests/kv/kv-spec.ts +0 -20
- package/tests/lists/First.test.ts +0 -43
- package/tests/lists/Length.test.ts +0 -19
- package/tests/lists/Split.test.ts +0 -29
- package/tests/lists/UniqueForProp.spec.ts +0 -59
- package/tests/lists/asArray.test.ts +0 -109
- package/tests/lists/dictArr.test.ts +0 -110
- package/tests/literal-spec.ts +0 -82
- package/tests/literals/AllCaps.spec.ts +0 -33
- package/tests/literals/CamelCase.spec.ts +0 -109
- package/tests/literals/Dasherize.spec.ts +0 -107
- package/tests/literals/EnsureStripLeadingTrailing.test.ts +0 -79
- package/tests/literals/HasUppercase.spec.ts +0 -33
- package/tests/literals/PascalCase.spec.ts +0 -109
- package/tests/literals/PathJoin.test.ts +0 -111
- package/tests/literals/SnakeCase.spec.ts +0 -109
- package/tests/literals/box.test.ts +0 -85
- package/tests/literals/whitespace-capture.spec.ts +0 -60
- package/tests/mapValues-spec.ts +0 -50
- package/tests/props-spec.ts +0 -234
- package/tests/runtime/condition.spec.ts +0 -19
- package/tests/runtime/if-is.spec.ts +0 -390
- package/tests/runtime/map-and-convert.test.ts +0 -31
- package/tests/runtime/type.spec.ts +0 -190
- package/tests/strArrayToDict-spec.ts +0 -40
- package/tests/tuples/TupleToUnion.spec.ts +0 -20
- package/tests/withValue.spec.ts +0 -173
- package/tsconfig.json +0 -36
- package/vitest.config.ts +0 -17
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { dictionaryTransform, ExplicitFunction } from "../src/runtime";
|
|
3
|
-
import { Expect, Equal, NotEqual, ExpectExtends, ExpectFalse } from "@type-challenges/utils";
|
|
4
|
-
import { ToFluent, Transformer } from "../src/types";
|
|
5
|
-
|
|
6
|
-
describe("dictionaryTransform()", () => {
|
|
7
|
-
type A = { foo: string; bar: string };
|
|
8
|
-
const a: A = { foo: "1", bar: "2" };
|
|
9
|
-
type F = { foo: () => string; bar: () => string };
|
|
10
|
-
const f: F = { foo: () => "1", bar: () => "2" };
|
|
11
|
-
type F2 = { foo: (n: number) => string; bar: (a: number, b: number) => string };
|
|
12
|
-
// const f2: F2 = { foo: (n: number) => `${n}`, bar: (a: number, b: number) => `${a * b}` };
|
|
13
|
-
|
|
14
|
-
// B typed
|
|
15
|
-
type B = { foo: number; bar: number };
|
|
16
|
-
// B typed as literal
|
|
17
|
-
type BL = { foo: 1; bar: 2 };
|
|
18
|
-
const b = { foo: 1, bar: 2 };
|
|
19
|
-
// B inferred
|
|
20
|
-
type BI = typeof b;
|
|
21
|
-
|
|
22
|
-
const createMutationApi = (state: { foo: number }) => {
|
|
23
|
-
const api = {
|
|
24
|
-
increment() {
|
|
25
|
-
return { ...state, foo: state.foo + 1 };
|
|
26
|
-
},
|
|
27
|
-
decrement() {
|
|
28
|
-
return { ...state, foo: state.foo - 1 };
|
|
29
|
-
},
|
|
30
|
-
set(v: number) {
|
|
31
|
-
return { ...state, foo: v };
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
getState() {
|
|
35
|
-
return state;
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
return api;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
type State = { foo: number };
|
|
43
|
-
const state: State = { foo: 0 };
|
|
44
|
-
|
|
45
|
-
type MutApi = { inc: () => State; dec: () => State; set: (n: number) => State };
|
|
46
|
-
const mutApi: MutApi = {
|
|
47
|
-
inc() {
|
|
48
|
-
return { ...state, foo: state.foo + 1 };
|
|
49
|
-
},
|
|
50
|
-
dec() {
|
|
51
|
-
return { ...state, foo: state.foo - 1 };
|
|
52
|
-
},
|
|
53
|
-
set(n: number) {
|
|
54
|
-
return { ...state, foo: n };
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
type FluentApi = { inc: () => FluentApi; dec: () => FluentApi; set: (n: number) => FluentApi };
|
|
58
|
-
const fluentApi: FluentApi = {
|
|
59
|
-
inc() {
|
|
60
|
-
state.foo = mutApi.inc().foo;
|
|
61
|
-
return fluentApi;
|
|
62
|
-
},
|
|
63
|
-
dec() {
|
|
64
|
-
state.foo = mutApi.dec().foo;
|
|
65
|
-
return fluentApi;
|
|
66
|
-
},
|
|
67
|
-
set(n: number) {
|
|
68
|
-
state.foo = mutApi.set(n).foo;
|
|
69
|
-
return fluentApi;
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
type SyntheticFluent = ToFluent<MutApi>;
|
|
73
|
-
|
|
74
|
-
it("simple dictionary with strings converted to numbers", () => {
|
|
75
|
-
const transform: Transformer<A, B> = (i, k) => {
|
|
76
|
-
return Number(i[k]);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const t = dictionaryTransform(a, transform);
|
|
80
|
-
type T = typeof t;
|
|
81
|
-
|
|
82
|
-
type cases = [
|
|
83
|
-
// wide type of string should now be number
|
|
84
|
-
Expect<Equal<T, B>>,
|
|
85
|
-
Expect<Equal<T, BI>>,
|
|
86
|
-
Expect<ExpectExtends<T, B>>,
|
|
87
|
-
Expect<ExpectExtends<T, BI>>,
|
|
88
|
-
// literals will not be involved here
|
|
89
|
-
Expect<NotEqual<T, BL>>,
|
|
90
|
-
// the literal _does_ extend the wider type
|
|
91
|
-
Expect<ExpectExtends<T, BL>>,
|
|
92
|
-
// but not the reverse
|
|
93
|
-
ExpectFalse<ExpectExtends<BL, T>>
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
const cases: cases = [true, true, true, true, true, true, false];
|
|
97
|
-
expect(cases).toBe(cases);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("simple function based dictionary <F> converted to numbers <B>", () => {
|
|
101
|
-
const transform: Transformer<F, B> = (i, k) => {
|
|
102
|
-
return Number(i[k]());
|
|
103
|
-
};
|
|
104
|
-
const t = dictionaryTransform(f, transform);
|
|
105
|
-
type T = typeof t;
|
|
106
|
-
|
|
107
|
-
type cases = [
|
|
108
|
-
// wide type of string should now be number
|
|
109
|
-
Expect<Equal<T, B>>,
|
|
110
|
-
Expect<Equal<T, BI>>,
|
|
111
|
-
Expect<ExpectExtends<T, B>>,
|
|
112
|
-
Expect<ExpectExtends<T, BI>>,
|
|
113
|
-
// literals will not be involved here
|
|
114
|
-
Expect<NotEqual<T, BL>>,
|
|
115
|
-
// the literal _does_ extend the wider type
|
|
116
|
-
Expect<ExpectExtends<T, BL>>,
|
|
117
|
-
// but not the reverse
|
|
118
|
-
ExpectFalse<ExpectExtends<BL, T>>
|
|
119
|
-
];
|
|
120
|
-
|
|
121
|
-
const cases: cases = [true, true, true, true, true, true, false];
|
|
122
|
-
expect(cases).toBe(cases);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it("function with variant parameters <F2> converted to numbers <B>", () => {
|
|
126
|
-
const transform: Transformer<F2, B> = (i, k) => {
|
|
127
|
-
switch (k) {
|
|
128
|
-
case "foo":
|
|
129
|
-
return Number(i[k](4));
|
|
130
|
-
case "bar":
|
|
131
|
-
return Number(i[k](1, 2));
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
const t = dictionaryTransform(f, transform);
|
|
135
|
-
type T = typeof t;
|
|
136
|
-
|
|
137
|
-
type cases = [
|
|
138
|
-
// wide type of string should now be number
|
|
139
|
-
Expect<Equal<T, B>>,
|
|
140
|
-
Expect<Equal<T, BI>>,
|
|
141
|
-
Expect<ExpectExtends<T, B>>,
|
|
142
|
-
Expect<ExpectExtends<T, BI>>,
|
|
143
|
-
// literals will not be involved here
|
|
144
|
-
Expect<NotEqual<T, BL>>,
|
|
145
|
-
// the literal _does_ extend the wider type
|
|
146
|
-
Expect<ExpectExtends<T, BL>>,
|
|
147
|
-
// but not the reverse
|
|
148
|
-
ExpectFalse<ExpectExtends<BL, T>>
|
|
149
|
-
];
|
|
150
|
-
|
|
151
|
-
const cases: cases = [true, true, true, true, true, true, false];
|
|
152
|
-
expect(cases).toBe(cases);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("A mutation function can can be transformed into a fluent API", () => {
|
|
156
|
-
const state = { foo: 0 };
|
|
157
|
-
const api = createMutationApi(state);
|
|
158
|
-
type A = typeof api;
|
|
159
|
-
// the mutation api performs as expected
|
|
160
|
-
// this includes returning the state after any call
|
|
161
|
-
expect(api.increment().foo).toBe(1);
|
|
162
|
-
expect(api.decrement().foo).toBe(-1);
|
|
163
|
-
// the one exception is getState which just returns the value
|
|
164
|
-
expect(api.getState().foo).toBe(0);
|
|
165
|
-
|
|
166
|
-
// transform function
|
|
167
|
-
const transform: Transformer<A, ToFluent<A>> = (i, k) => {
|
|
168
|
-
switch (k) {
|
|
169
|
-
case "getState":
|
|
170
|
-
return () => {
|
|
171
|
-
return dictionaryTransform(api, transform);
|
|
172
|
-
};
|
|
173
|
-
case "set":
|
|
174
|
-
case "decrement":
|
|
175
|
-
case "increment":
|
|
176
|
-
const fn = ExplicitFunction(i[k]);
|
|
177
|
-
return (...args: Parameters<typeof fn>) => {
|
|
178
|
-
fn(...args);
|
|
179
|
-
// this is cheating as runtime is not updated
|
|
180
|
-
return dictionaryTransform(api, transform);
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const t = dictionaryTransform(api, transform);
|
|
186
|
-
type T = typeof t;
|
|
187
|
-
|
|
188
|
-
// the transformed API is fluent and so calls to the API should return
|
|
189
|
-
// the same API surface
|
|
190
|
-
expect(typeof t.increment().increment).toBe("function");
|
|
191
|
-
expect(typeof t.decrement().increment).toBe("function");
|
|
192
|
-
// this even applies to getState() which no longer has any useful utility
|
|
193
|
-
expect(typeof t.getState().increment).toBe("function");
|
|
194
|
-
// this pattern should continue indefinitely
|
|
195
|
-
expect(typeof t.increment().decrement().increment().decrement).toBe("function");
|
|
196
|
-
|
|
197
|
-
// beyond the run-time system, we must check that all types are expected
|
|
198
|
-
type cases = [
|
|
199
|
-
// All functions return the same API defined by T
|
|
200
|
-
Expect<Equal<ReturnType<T["increment"]>, T>>,
|
|
201
|
-
Expect<Equal<ReturnType<T["decrement"]>, T>>,
|
|
202
|
-
Expect<Equal<ReturnType<T["set"]>, T>>,
|
|
203
|
-
Expect<Equal<ReturnType<T["getState"]>, T>>,
|
|
204
|
-
// set() has a distinct set of parameters from other methods
|
|
205
|
-
Expect<NotEqual<Parameters<T["increment"]>, Parameters<T["set"]>>>,
|
|
206
|
-
// whereas the rest on this API are the same
|
|
207
|
-
Expect<Equal<Parameters<T["increment"]>, Parameters<T["decrement"]>>>
|
|
208
|
-
];
|
|
209
|
-
const cases: cases = [true, true, true, true, true, true];
|
|
210
|
-
expect(cases).toBe(cases);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it("Explicit mutation API and fluent API", () => {
|
|
214
|
-
const transform: Transformer<MutApi, FluentApi> = (i, k) => {
|
|
215
|
-
switch (k) {
|
|
216
|
-
case "dec":
|
|
217
|
-
case "inc":
|
|
218
|
-
return () => {
|
|
219
|
-
i[k](); // mutate state
|
|
220
|
-
return fluentApi;
|
|
221
|
-
};
|
|
222
|
-
case "set":
|
|
223
|
-
return (n: number) => {
|
|
224
|
-
i[k](n); // mutate state
|
|
225
|
-
return fluentApi;
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const t = dictionaryTransform(mutApi, transform);
|
|
231
|
-
type T = typeof t;
|
|
232
|
-
|
|
233
|
-
type cases = [
|
|
234
|
-
// the explicit definition of the Fluent API is
|
|
235
|
-
// the same as the synthetic version created with ToFluent
|
|
236
|
-
Expect<Equal<FluentApi, SyntheticFluent>>,
|
|
237
|
-
// the fluent API derived from the dictionary transform is
|
|
238
|
-
// also the same as the explicit and synthetic
|
|
239
|
-
Expect<Equal<FluentApi, T>>
|
|
240
|
-
];
|
|
241
|
-
const cases: cases = [true, true];
|
|
242
|
-
expect(cases).toBe(cases);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it("using dictionaryTransform recursively for fluent API works at both runtime and designtime", () => {
|
|
246
|
-
const transform: Transformer<MutApi, FluentApi> = (i, k) => {
|
|
247
|
-
switch (k) {
|
|
248
|
-
case "dec":
|
|
249
|
-
case "inc":
|
|
250
|
-
return () => {
|
|
251
|
-
state.foo = i[k]().foo; // mutate state, assign to global "state"
|
|
252
|
-
return dictionaryTransform(mutApi, transform);
|
|
253
|
-
};
|
|
254
|
-
case "set":
|
|
255
|
-
return (n: number) => {
|
|
256
|
-
state.foo = i[k](n).foo; // mutate state
|
|
257
|
-
return dictionaryTransform(mutApi, transform);
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const t = dictionaryTransform(mutApi, transform);
|
|
263
|
-
type T = typeof t;
|
|
264
|
-
|
|
265
|
-
type cases = [
|
|
266
|
-
// the fluent API derived from recursive calls to dictionaryTransform
|
|
267
|
-
// is seen as the same type the explictly deinfined type.
|
|
268
|
-
Expect<Equal<FluentApi, T>>
|
|
269
|
-
];
|
|
270
|
-
const cases: cases = [true];
|
|
271
|
-
expect(cases).toBe(cases);
|
|
272
|
-
|
|
273
|
-
t.set(0);
|
|
274
|
-
expect(state.foo).toBe(0);
|
|
275
|
-
t.set(1);
|
|
276
|
-
expect(state.foo).toBe(1);
|
|
277
|
-
t.set(0).inc().inc();
|
|
278
|
-
expect(state.foo).toBe(2);
|
|
279
|
-
});
|
|
280
|
-
});
|
package/tests/ifTypeOf-spec.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
|
-
import { Expect, Equal } from "@type-challenges/utils";
|
|
5
|
-
import { defineType, literal } from "../src/runtime";
|
|
6
|
-
import { ifTypeOf } from "src/runtime/type-checks/ifTypeOf";
|
|
7
|
-
|
|
8
|
-
describe("ifTypeOf() utility", () => {
|
|
9
|
-
it("base validation with extends() returns true/false", () => {
|
|
10
|
-
const target = { foo: "", bar: 0 };
|
|
11
|
-
const yup = ifTypeOf({ foo: "foo", bar: 42 }).extends(target);
|
|
12
|
-
const nope = ifTypeOf({ foo: "foo", bar: "whoops" }).extends(target);
|
|
13
|
-
|
|
14
|
-
expect(yup).toBe(true);
|
|
15
|
-
expect(nope).toBe(false);
|
|
16
|
-
|
|
17
|
-
type cases = [Expect<Equal<typeof yup, true>>, Expect<Equal<typeof nope, false>>];
|
|
18
|
-
const cases: cases = [true, true];
|
|
19
|
-
expect(cases).toBe(cases);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("base validation of narrowlyExtends() returns true/false", () => {
|
|
23
|
-
const target = defineType({ bar: 0 })({ foo: "foo" });
|
|
24
|
-
const yup = ifTypeOf({ foo: "foo", bar: 0 }).extends(target);
|
|
25
|
-
const yup2 = ifTypeOf({ foo: "foey", bar: 0 }).extends(target);
|
|
26
|
-
const nope1 = ifTypeOf({ foo: "foo", bar: 42 }).narrowlyExtends(target);
|
|
27
|
-
const nope2 = ifTypeOf({ foo: "foo", bar: "whoops" }).extends(target);
|
|
28
|
-
|
|
29
|
-
expect(yup).toBe(true);
|
|
30
|
-
expect(yup2).toBe(true);
|
|
31
|
-
expect(nope1).toBe(false);
|
|
32
|
-
expect(nope2).toBe(false);
|
|
33
|
-
|
|
34
|
-
type cases = [
|
|
35
|
-
Expect<Equal<typeof yup, true>>,
|
|
36
|
-
Expect<Equal<typeof yup2, true>>,
|
|
37
|
-
Expect<Equal<typeof nope1, false>>,
|
|
38
|
-
Expect<Equal<typeof nope2, false>>
|
|
39
|
-
];
|
|
40
|
-
const cases: cases = [true, true, true, true];
|
|
41
|
-
expect(cases).toBe(cases);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("validation of non-dictionary types works as expected too", () => {
|
|
45
|
-
const target = 42 as number;
|
|
46
|
-
const t2 = literal(42);
|
|
47
|
-
|
|
48
|
-
const numToNum = ifTypeOf(55).extends(target);
|
|
49
|
-
const wideNumCompare = ifTypeOf(0).extends(target);
|
|
50
|
-
const narrowEquality = ifTypeOf(42).narrowlyExtends(t2);
|
|
51
|
-
const stringIsNumber = ifTypeOf("foo").extends(target);
|
|
52
|
-
const diffNumbersNarrowly = ifTypeOf(12).narrowlyExtends(t2);
|
|
53
|
-
|
|
54
|
-
expect(numToNum).toBe(true);
|
|
55
|
-
expect(wideNumCompare).toBe(true);
|
|
56
|
-
expect(narrowEquality).toBe(true);
|
|
57
|
-
expect(stringIsNumber).toBe(false);
|
|
58
|
-
expect(diffNumbersNarrowly).toBe(false);
|
|
59
|
-
|
|
60
|
-
type cases = [
|
|
61
|
-
Expect<Equal<typeof numToNum, true>>,
|
|
62
|
-
Expect<Equal<typeof wideNumCompare, true>>,
|
|
63
|
-
Expect<Equal<typeof narrowEquality, true>>,
|
|
64
|
-
Expect<Equal<typeof stringIsNumber, false>>,
|
|
65
|
-
Expect<Equal<typeof diffNumbersNarrowly, false>>
|
|
66
|
-
];
|
|
67
|
-
const cases: cases = [true, true, true, true, true];
|
|
68
|
-
expect(cases).toBe(cases);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("validation of function types works when expressed widely", () => {
|
|
72
|
-
const target: Function = () => "";
|
|
73
|
-
const fn = () => "hi";
|
|
74
|
-
const fnExtends = ifTypeOf(fn).extends(target);
|
|
75
|
-
|
|
76
|
-
expect(fnExtends).toBe(true);
|
|
77
|
-
|
|
78
|
-
type cases = [Expect<Equal<typeof fnExtends, true>>];
|
|
79
|
-
const cases: cases = [true];
|
|
80
|
-
expect(cases).toBe(cases);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("checklist example", () => {
|
|
84
|
-
const noFoodOrDrink = ifTypeOf({ wakeUp: true }).extends({
|
|
85
|
-
wakeUp: true,
|
|
86
|
-
eatBreakfast: true,
|
|
87
|
-
drinkCoffee: true,
|
|
88
|
-
});
|
|
89
|
-
const ready = ifTypeOf({ wakeUp: true, eatBreakfast: true, drinkCoffee: true }).extends({
|
|
90
|
-
wakeUp: true,
|
|
91
|
-
eatBreakfast: true,
|
|
92
|
-
drinkCoffee: true,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// completely wrong
|
|
96
|
-
const fullyBaked = ifTypeOf({ wakeUp: false, eatBreakfast: false, drinkCoffee: false }).extends(
|
|
97
|
-
{ wakeUp: true, eatBreakfast: true, drinkCoffee: true }
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
// half-right
|
|
101
|
-
const halfBaked = ifTypeOf({ wakeUp: false, eatBreakfast: false, drinkCoffee: false }).extends({
|
|
102
|
-
wakeUp: true,
|
|
103
|
-
eatBreakfast: true,
|
|
104
|
-
drinkCoffee: true,
|
|
105
|
-
} as const);
|
|
106
|
-
|
|
107
|
-
// back to right; at the cost of being very careful
|
|
108
|
-
const lucid = ifTypeOf({
|
|
109
|
-
wakeUp: false,
|
|
110
|
-
eatBreakfast: false,
|
|
111
|
-
drinkCoffee: false,
|
|
112
|
-
}).narrowlyExtends({ wakeUp: true, eatBreakfast: true, drinkCoffee: true } as const);
|
|
113
|
-
|
|
114
|
-
// run-time tests of False Positives
|
|
115
|
-
// ---------------------------------
|
|
116
|
-
expect(noFoodOrDrink).toBe(false);
|
|
117
|
-
expect(ready).toBe(true);
|
|
118
|
-
|
|
119
|
-
// here we'll show how narrow types need to be
|
|
120
|
-
// made explicit to both type and run time systems
|
|
121
|
-
|
|
122
|
-
// in "fullyBaked" both run-time and type system are wrong functionally
|
|
123
|
-
// but they report as true
|
|
124
|
-
expect(fullyBaked).toBe(true);
|
|
125
|
-
// we can get to a half-way house by expressing the type as "as const" and making it's types
|
|
126
|
-
// literals; now the type system report "false" and the runtime says "true"
|
|
127
|
-
expect(halfBaked).toBe(true);
|
|
128
|
-
// to get to a fully working solution we need to use the `narrowlyDefines` operator
|
|
129
|
-
// along with the "as const" for the type system
|
|
130
|
-
expect(lucid).toBe(false);
|
|
131
|
-
|
|
132
|
-
// type tests
|
|
133
|
-
type FalsePositives = [
|
|
134
|
-
Expect<Equal<typeof noFoodOrDrink, false>>,
|
|
135
|
-
Expect<Equal<typeof fullyBaked, true>>,
|
|
136
|
-
Expect<Equal<typeof halfBaked, false>>,
|
|
137
|
-
Expect<Equal<typeof lucid, false>>
|
|
138
|
-
];
|
|
139
|
-
const falsePositives: FalsePositives = [true, true, true, true];
|
|
140
|
-
expect(falsePositives).toBe(falsePositives);
|
|
141
|
-
|
|
142
|
-
// but now we have to accept that the type might be a combination of both
|
|
143
|
-
// literal types and broader types; this is not hard to express with types
|
|
144
|
-
// but it makes our approach much more awkward and the API much more cumbersome
|
|
145
|
-
|
|
146
|
-
// here we see a type that represents this challenge but how it fails with
|
|
147
|
-
// with the runtime
|
|
148
|
-
|
|
149
|
-
const literal = { foo: 1 } as const;
|
|
150
|
-
const wide = { bar: "hi" };
|
|
151
|
-
const hybrid = { ...literal, ...wide };
|
|
152
|
-
const toughLuck = ifTypeOf({ foo: 1, bar: "bye" }).narrowlyExtends(hybrid);
|
|
153
|
-
|
|
154
|
-
// toughLuck should be TRUE because both bar's are strings
|
|
155
|
-
// but because we need to preserve run-time literal checking on "foo"
|
|
156
|
-
// it is doing it on both
|
|
157
|
-
expect(toughLuck).toBe(false);
|
|
158
|
-
|
|
159
|
-
type HybridTests = [
|
|
160
|
-
// foo is a literal, bar is wide
|
|
161
|
-
Expect<Equal<typeof hybrid, { foo: 1; bar: string }>>,
|
|
162
|
-
// and type system correctly evaluates
|
|
163
|
-
Expect<Equal<typeof toughLuck, true>>
|
|
164
|
-
];
|
|
165
|
-
const ToughLuck: HybridTests = [true, true];
|
|
166
|
-
expect(ToughLuck).toBe(ToughLuck);
|
|
167
|
-
|
|
168
|
-
// in addition to this hybrid issue, i'm not sure there is a good
|
|
169
|
-
// way to do a narrow type check on a function; we can hit some use
|
|
170
|
-
// cases by converting to a string but that's incomplete
|
|
171
|
-
const fn = (_c: number) => "string";
|
|
172
|
-
const fn2 = (_c: number) => "string";
|
|
173
|
-
const genericFn: Function = () => "string";
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
const narrow = ifTypeOf(fn).narrowlyExtends(fn2);
|
|
177
|
-
const asWellAsGeneric = ifTypeOf(fn).narrowlyExtends(genericFn);
|
|
178
|
-
// the type checks shows that the type system is fine
|
|
179
|
-
type Functions = [
|
|
180
|
-
Expect<Equal<typeof narrow, true>>,
|
|
181
|
-
Expect<Equal<typeof asWellAsGeneric, true>>
|
|
182
|
-
];
|
|
183
|
-
const functions: Functions = [true, true];
|
|
184
|
-
expect(functions).toBe(functions);
|
|
185
|
-
throw new Error("The attempt to run narrowlyExtends on a function should throw an error");
|
|
186
|
-
} catch {
|
|
187
|
-
// there is no way to narrow compare functions and so it throws
|
|
188
|
-
// an error to the run time system
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { Equal, Expect } from "@type-challenges/utils";
|
|
4
|
-
import { KeyValue } from "src/types";
|
|
5
|
-
|
|
6
|
-
describe("KeyValue<T, K> type utility", () => {
|
|
7
|
-
it("explicit KeyValue<T,K> definitions retain literal type info", () => {
|
|
8
|
-
const obj = { foo: 1, bar: "hi", baz: { a: 1, b: 2 } } as const;
|
|
9
|
-
type O = typeof obj;
|
|
10
|
-
type Foo = KeyValue<O, "foo">;
|
|
11
|
-
type Bar = KeyValue<O, "bar">;
|
|
12
|
-
type Baz = KeyValue<O, "baz">;
|
|
13
|
-
|
|
14
|
-
type cases = [
|
|
15
|
-
Expect<Equal<Foo, ["foo", 1]>>,
|
|
16
|
-
Expect<Equal<Bar, ["bar", "hi"]>>,
|
|
17
|
-
Expect<Equal<Baz, ["baz", { readonly a: 1; readonly b: 2 }]>>
|
|
18
|
-
];
|
|
19
|
-
const c: cases = [true, true, true];
|
|
20
|
-
expect(c).toBe(c);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { Equal, Expect, ExpectFalse } from "@type-challenges/utils";
|
|
4
|
-
import { SameKeys } from "src/types";
|
|
5
|
-
|
|
6
|
-
describe("SameKeys<T> utility", () => {
|
|
7
|
-
it("keys must be same type but value can be anything", () => {
|
|
8
|
-
const origin = { id: "abc", favorite: false };
|
|
9
|
-
type O = typeof origin;
|
|
10
|
-
type SK = SameKeys<O>;
|
|
11
|
-
|
|
12
|
-
type cases = [Expect<Equal<SK, { id: any; favorite: any }>>];
|
|
13
|
-
const c: cases = [true];
|
|
14
|
-
expect(c).toBe(c);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("explicit assignment does enforce exhaustion of all keys", () => {
|
|
18
|
-
const origin = { id: "abc", favorite: false };
|
|
19
|
-
const partial = { id: "abc" };
|
|
20
|
-
type O = typeof origin;
|
|
21
|
-
type P = typeof partial;
|
|
22
|
-
|
|
23
|
-
type cases = [
|
|
24
|
-
// not surprisingly appling utility to both
|
|
25
|
-
// does not reach equality
|
|
26
|
-
ExpectFalse<Equal<SameKeys<O>, SameKeys<P>>>,
|
|
27
|
-
// but more importantly P can not be assigned to SameKeys<O>
|
|
28
|
-
// this ensures that you'd get a type error with:
|
|
29
|
-
// `const p: SameKeys<O> = { id: "abc" }`
|
|
30
|
-
ExpectFalse<Equal<SameKeys<O>, P>>
|
|
31
|
-
];
|
|
32
|
-
const c: cases = [false, false];
|
|
33
|
-
expect(c).toBe(c);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { Equal, Expect, NotEqual } from "@type-challenges/utils";
|
|
4
|
-
import { dictToKv, kvToDict } from "src/runtime/dictionary";
|
|
5
|
-
import { DictFromKv } from "src/types/kv";
|
|
6
|
-
import { keys } from "src/runtime";
|
|
7
|
-
|
|
8
|
-
describe("dictToKv()", () => {
|
|
9
|
-
it.skip("basic structure is correct when forcing to Tuple structure", () => {
|
|
10
|
-
const obj = { id: 123, foo: "bar" } as const;
|
|
11
|
-
const val = dictToKv(obj, true);
|
|
12
|
-
|
|
13
|
-
expect(Array.isArray(val)).toBeTruthy();
|
|
14
|
-
expect(val).toHaveLength(2);
|
|
15
|
-
expect(val.every((i) => Object.keys(i).includes("key"))).toBeTruthy();
|
|
16
|
-
expect(val.every((i) => Object.keys(i).includes("value"))).toBeTruthy();
|
|
17
|
-
|
|
18
|
-
for (const kv of val) {
|
|
19
|
-
if (kv.key === "id") {
|
|
20
|
-
type cases = [Expect<Equal<typeof kv.key, "id">>, Expect<Equal<typeof kv.value, 123>>];
|
|
21
|
-
const c: cases = [true, true];
|
|
22
|
-
expect(c).toBe(c);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// TODO: this actually passes some of the time in CLI test and almost always in vs-code
|
|
27
|
-
|
|
28
|
-
// type cases = [
|
|
29
|
-
// Expect<
|
|
30
|
-
// Equal<
|
|
31
|
-
// Val,
|
|
32
|
-
// [
|
|
33
|
-
// {
|
|
34
|
-
// key: "id";
|
|
35
|
-
// value: 123;
|
|
36
|
-
// },
|
|
37
|
-
// {
|
|
38
|
-
// key: "foo";
|
|
39
|
-
// value: "bar";
|
|
40
|
-
// }
|
|
41
|
-
// ]
|
|
42
|
-
// >
|
|
43
|
-
// >
|
|
44
|
-
// ];
|
|
45
|
-
|
|
46
|
-
// const c: cases = [true];
|
|
47
|
-
// expect(c).toBe(c);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("basic structure is correct when using array structure", () => {
|
|
52
|
-
const obj = { id: 123, foo: "bar" } as const;
|
|
53
|
-
const val = dictToKv(obj);
|
|
54
|
-
|
|
55
|
-
expect(Array.isArray(val)).toBeTruthy();
|
|
56
|
-
expect(val).toHaveLength(2);
|
|
57
|
-
expect(val.every((i) => Object.keys(i).includes("key"))).toBeTruthy();
|
|
58
|
-
expect(val.every((i) => Object.keys(i).includes("value"))).toBeTruthy();
|
|
59
|
-
|
|
60
|
-
for (const kv of val) {
|
|
61
|
-
if (kv.key === "id") {
|
|
62
|
-
type cases = [Expect<Equal<typeof kv.key, "id">>, Expect<Equal<typeof kv.value, 123>>];
|
|
63
|
-
const c: cases = [true, true];
|
|
64
|
-
expect(c).toBe(c);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// types are a bit ugly so skipping check when not Tuple type
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe("kvToDict()", () => {
|
|
72
|
-
it("the DictFromKv<T> utility returns original object type", () => {
|
|
73
|
-
const val = dictToKv({ id: 123, foo: "bar" });
|
|
74
|
-
type Back = DictFromKv<typeof val>;
|
|
75
|
-
|
|
76
|
-
type cases = [Expect<Equal<Back, { id: 123; foo: "bar" }>>];
|
|
77
|
-
const c: cases = [true];
|
|
78
|
-
expect(c).toBe(c);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it("originating KeyValue array converts to strongly typed dictionary", () => {
|
|
82
|
-
const obj = kvToDict([
|
|
83
|
-
{ key: "id", value: "abcd" },
|
|
84
|
-
{ key: "color", value: "red" },
|
|
85
|
-
{ key: "favorite", value: true as boolean },
|
|
86
|
-
]);
|
|
87
|
-
type Obj = typeof obj;
|
|
88
|
-
type Keys = keyof Obj;
|
|
89
|
-
|
|
90
|
-
expect(obj.id).toBe("abcd");
|
|
91
|
-
expect(obj.color).toBe("red");
|
|
92
|
-
expect(obj.favorite).toBe(true);
|
|
93
|
-
expect(Object.keys(obj)).toHaveLength(3);
|
|
94
|
-
|
|
95
|
-
type cases = [
|
|
96
|
-
// Keys are known explicitly
|
|
97
|
-
Expect<Equal<Keys, "id" | "color" | "favorite">>,
|
|
98
|
-
// Values are literal values where available
|
|
99
|
-
Expect<Equal<Obj["id"], "abcd">>,
|
|
100
|
-
Expect<Equal<Obj["color"], "red">>,
|
|
101
|
-
// if source is wide, then resolution is wide
|
|
102
|
-
Expect<Equal<Obj["favorite"], boolean>>
|
|
103
|
-
];
|
|
104
|
-
|
|
105
|
-
const c: cases = [true, true, true, true];
|
|
106
|
-
expect(c).toBe(c);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe("kvToDict / dictToKv inverse", () => {
|
|
111
|
-
it("run-time inverts correctly (starting with obj)", () => {
|
|
112
|
-
const obj = { id: 123, foo: "bar" } as const;
|
|
113
|
-
const inverse = kvToDict(dictToKv(obj));
|
|
114
|
-
|
|
115
|
-
expect(keys(inverse).every((i) => inverse[i] === obj[i]));
|
|
116
|
-
});
|
|
117
|
-
it("run-time inverts correctly (starting with array)", () => {
|
|
118
|
-
const arr = [
|
|
119
|
-
{ key: "id", value: 123 },
|
|
120
|
-
{ key: "foo", value: "bar" },
|
|
121
|
-
] as const;
|
|
122
|
-
const inverse = dictToKv(kvToDict(arr));
|
|
123
|
-
|
|
124
|
-
expect(inverse).toEqual(arr);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("typing inverts correctly (starting with obj)", () => {
|
|
128
|
-
const obj = { id: 123, foo: "bar" } as const;
|
|
129
|
-
const inverse = kvToDict(dictToKv(obj));
|
|
130
|
-
type Obj = typeof obj;
|
|
131
|
-
type Inverse = typeof inverse;
|
|
132
|
-
|
|
133
|
-
type cases = [
|
|
134
|
-
// while not precisely equal (due to readonly)
|
|
135
|
-
Expect<NotEqual<Inverse, Obj>>,
|
|
136
|
-
// they are equal in each key/value pair
|
|
137
|
-
Expect<Equal<Inverse["id"], Obj["id"]>>,
|
|
138
|
-
Expect<Equal<Inverse["foo"], Obj["foo"]>>
|
|
139
|
-
];
|
|
140
|
-
const c: cases = [true, true, true];
|
|
141
|
-
expect(c).toBe(c);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("typing inverts correctly (starting with arr)", () => {
|
|
145
|
-
const arr = [
|
|
146
|
-
{ key: "id", value: 123 },
|
|
147
|
-
{ key: "foo", value: "bar" },
|
|
148
|
-
] as const;
|
|
149
|
-
const inverse = dictToKv(
|
|
150
|
-
kvToDict([
|
|
151
|
-
{ key: "id", value: 123 },
|
|
152
|
-
{ key: "foo", value: "bar" },
|
|
153
|
-
])
|
|
154
|
-
);
|
|
155
|
-
type Arr = typeof arr;
|
|
156
|
-
type Inverse = typeof inverse[0];
|
|
157
|
-
|
|
158
|
-
if (inverse[0].key === "id") {
|
|
159
|
-
type cases = [
|
|
160
|
-
// while not precisely equal (due to readonly)
|
|
161
|
-
Expect<NotEqual<Inverse, Arr>>
|
|
162
|
-
// they are equal in each key/value pair
|
|
163
|
-
// Expect<ExpectExtends<Arr, Inverse>>
|
|
164
|
-
];
|
|
165
|
-
const c: cases = [true];
|
|
166
|
-
expect(c).toBe(c);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
});
|