ts-fortress 4.0.0 → 4.1.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/entry-point.mjs +1 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/record/index.d.mts +1 -0
- package/dist/record/index.d.mts.map +1 -1
- package/dist/record/index.mjs +1 -0
- package/dist/record/index.mjs.map +1 -1
- package/dist/record/record.d.mts +2 -2
- package/dist/record/record.d.mts.map +1 -1
- package/dist/record/valueof.d.mts +8 -0
- package/dist/record/valueof.d.mts.map +1 -0
- package/dist/record/valueof.mjs +23 -0
- package/dist/record/valueof.mjs.map +1 -0
- package/package.json +1 -1
- package/src/record/index.mts +1 -0
- package/src/record/record.mts +1 -1
- package/src/record/valueof.mts +57 -0
- package/src/record/valueof.test.mts +178 -0
package/dist/entry-point.mjs
CHANGED
|
@@ -52,6 +52,7 @@ export { isOptionalProperty, optional } from './record/optional.mjs';
|
|
|
52
52
|
export { partial } from './record/partial.mjs';
|
|
53
53
|
export { pick } from './record/pick.mjs';
|
|
54
54
|
export { record, strictRecord } from './record/record.mjs';
|
|
55
|
+
export { valueof } from './record/valueof.mjs';
|
|
55
56
|
export { createAssertFn } from './utils/create-assert-fn.mjs';
|
|
56
57
|
export { createCastFn } from './utils/create-cast-fn.mjs';
|
|
57
58
|
export { createIsFn } from './utils/create-is-fn.mjs';
|
package/dist/entry-point.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -51,6 +51,7 @@ export { isOptionalProperty, optional } from './record/optional.mjs';
|
|
|
51
51
|
export { partial } from './record/partial.mjs';
|
|
52
52
|
export { pick } from './record/pick.mjs';
|
|
53
53
|
export { record, strictRecord } from './record/record.mjs';
|
|
54
|
+
export { valueof } from './record/valueof.mjs';
|
|
54
55
|
import 'ts-data-forge';
|
|
55
56
|
export { createAssertFn } from './utils/create-assert-fn.mjs';
|
|
56
57
|
export { createCastFn } from './utils/create-cast-fn.mjs';
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/record/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/record/index.mts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/record/index.mts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
package/dist/record/index.mjs
CHANGED
|
@@ -5,4 +5,5 @@ export { isOptionalProperty, optional } from './optional.mjs';
|
|
|
5
5
|
export { partial } from './partial.mjs';
|
|
6
6
|
export { pick } from './pick.mjs';
|
|
7
7
|
export { record, strictRecord } from './record.mjs';
|
|
8
|
+
export { valueof } from './valueof.mjs';
|
|
8
9
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
|
package/dist/record/record.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RecordType, type
|
|
1
|
+
import { type RecordType, type Type } from '../type.mjs';
|
|
2
2
|
export declare const record: <const R extends ReadonlyRecord<string, Type<unknown>>>(shape: R, options?: Partial<Readonly<{
|
|
3
3
|
typeName: string;
|
|
4
4
|
/** @default true */
|
|
@@ -27,5 +27,5 @@ export declare const record: <const R extends ReadonlyRecord<string, Type<unknow
|
|
|
27
27
|
*/
|
|
28
28
|
export declare const strictRecord: <const R extends ReadonlyRecord<string, Type<unknown>>>(source: R, options?: Partial<Readonly<{
|
|
29
29
|
typeName: string;
|
|
30
|
-
}>>) =>
|
|
30
|
+
}>>) => RecordType<R>;
|
|
31
31
|
//# sourceMappingURL=record.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.d.mts","sourceRoot":"","sources":["../../src/record/record.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"record.d.mts","sourceRoot":"","sources":["../../src/record/record.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,IAAI,EACV,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAC1E,OAAO,CAAC,EACR,UAAU,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IAEjB,oBAAoB;IACpB,qBAAqB,EAAE,OAAO,CAAC;CAChC,CAAC,CACH,KACA,UAAU,CAAC,CAAC,CAyGd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAErD,QAAQ,CAAC,EACT,UAAU,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,UAAU,CAAC,CAAC,CAC+C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RecordType, type Type } from '../type.mjs';
|
|
2
|
+
export declare const valueof: <const R extends ReadonlyRecord<string, Type<unknown>>>(recordType: RecordType<R>, options?: Partial<Readonly<{
|
|
3
|
+
typeName: string;
|
|
4
|
+
}>>) => ValueOfType<R>;
|
|
5
|
+
type ValueofTypeSub<R extends ReadonlyRecord<string, Type<unknown>>> = Type<R[keyof R]['defaultValue']>;
|
|
6
|
+
type ValueOfType<R extends ReadonlyRecord<string, Type<unknown>>> = IsNever<keyof R> extends true ? Type<undefined> : ValueofTypeSub<R>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=valueof.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valueof.d.mts","sourceRoot":"","sources":["../../src/record/valueof.mts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAEzD,eAAO,MAAM,OAAO,GAAI,KAAK,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAC3E,YAAY,UAAU,CAAC,CAAC,CAAC,EACzB,UAAU,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,WAAW,CAAC,CAAC,CAiBf,CAAC;AAEF,KAAK,cAAc,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,CACzE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAC3B,CAAC;AAEF,KAAK,WAAW,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAC9D,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Arr } from 'ts-data-forge';
|
|
2
|
+
import { union } from '../compose/union.mjs';
|
|
3
|
+
import { undefinedType } from '../primitives/undefined.mjs';
|
|
4
|
+
|
|
5
|
+
const valueof = (recordType, options) => {
|
|
6
|
+
const types = Object.values(recordType.shape);
|
|
7
|
+
if (Arr.isArrayAtLeastLength(types, 2)) {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
9
|
+
return union(types, {
|
|
10
|
+
typeName: options?.typeName ?? `ValueOf<${recordType.typeName}>`,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (Arr.isNonEmpty(types)) {
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
15
|
+
return types[0];
|
|
16
|
+
}
|
|
17
|
+
// types is empty
|
|
18
|
+
return undefinedType;
|
|
19
|
+
};
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
21
|
+
|
|
22
|
+
export { valueof };
|
|
23
|
+
//# sourceMappingURL=valueof.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"valueof.mjs","sources":["../../src/record/valueof.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;MAKa,OAAO,GAAG,CACrB,UAAyB,EACzB,OAIC,KACiB;IAClB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;IAE7C,IAAI,GAAG,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE;;QAEtC,OAAO,KAAK,CAAC,KAAK,EAAE;YAClB,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,CAAA,QAAA,EAAW,UAAU,CAAC,QAAQ,CAAA,CAAA,CAAG;AACjE,SAAA,CAA+C;;AAGlD,IAAA,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;;AAEzB,QAAA,OAAO,KAAK,CAAC,CAAC,CAA+C;;;AAI/D,IAAA,OAAO,aAAsC;AAC/C;AASA;;;;"}
|
package/package.json
CHANGED
package/src/record/index.mts
CHANGED
package/src/record/record.mts
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Arr, expectType } from 'ts-data-forge';
|
|
2
|
+
import { union } from '../compose/index.mjs';
|
|
3
|
+
import { undefinedType } from '../primitives/index.mjs';
|
|
4
|
+
import { type RecordType, type Type } from '../type.mjs';
|
|
5
|
+
|
|
6
|
+
export const valueof = <const R extends ReadonlyRecord<string, Type<unknown>>>(
|
|
7
|
+
recordType: RecordType<R>,
|
|
8
|
+
options?: Partial<
|
|
9
|
+
Readonly<{
|
|
10
|
+
typeName: string;
|
|
11
|
+
}>
|
|
12
|
+
>,
|
|
13
|
+
): ValueOfType<R> => {
|
|
14
|
+
const types = Object.values(recordType.shape);
|
|
15
|
+
|
|
16
|
+
if (Arr.isArrayAtLeastLength(types, 2)) {
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
18
|
+
return union(types, {
|
|
19
|
+
typeName: options?.typeName ?? `ValueOf<${recordType.typeName}>`,
|
|
20
|
+
}) satisfies ValueofTypeSub<R> as ValueOfType<R>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (Arr.isNonEmpty(types)) {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
25
|
+
return types[0] satisfies ValueofTypeSub<R> as ValueOfType<R>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// types is empty
|
|
29
|
+
return undefinedType satisfies ValueOfType<R>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type ValueofTypeSub<R extends ReadonlyRecord<string, Type<unknown>>> = Type<
|
|
33
|
+
R[keyof R]['defaultValue']
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
type ValueOfType<R extends ReadonlyRecord<string, Type<unknown>>> =
|
|
37
|
+
IsNever<keyof R> extends true ? Type<undefined> : ValueofTypeSub<R>;
|
|
38
|
+
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
40
|
+
expectType<ValueOfType<{}>, Type<undefined>>('=');
|
|
41
|
+
|
|
42
|
+
expectType<
|
|
43
|
+
ValueOfType<{ a: Type<0>; b: Type<1>; c: Type<2> }>,
|
|
44
|
+
Type<0 | 1 | 2>
|
|
45
|
+
>('=');
|
|
46
|
+
|
|
47
|
+
expectType<
|
|
48
|
+
ValueOfType<{ x: Type<string>; y: Type<number>; z: Type<boolean> }>,
|
|
49
|
+
Type<string | number | boolean>
|
|
50
|
+
>('=');
|
|
51
|
+
|
|
52
|
+
expectType<
|
|
53
|
+
ValueOfType<{ same: Type<string>; value: Type<string> }>,
|
|
54
|
+
Type<string>
|
|
55
|
+
>('=');
|
|
56
|
+
|
|
57
|
+
expectType<ValueOfType<{ never: Type<never> }>, Type<never>>('=');
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { expectType, Result } from 'ts-data-forge';
|
|
2
|
+
import { number, string } from '../primitives/index.mjs';
|
|
3
|
+
import { type Type, type TypeOf } from '../type.mjs';
|
|
4
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
5
|
+
import { record } from './record.mjs';
|
|
6
|
+
import { valueof } from './valueof.mjs';
|
|
7
|
+
|
|
8
|
+
describe('valueof', () => {
|
|
9
|
+
const ymdValue = valueof(
|
|
10
|
+
record({
|
|
11
|
+
year: number(1900),
|
|
12
|
+
month: number(1),
|
|
13
|
+
date: number(1),
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expectType<typeof ymdValue, Type<number>>('=');
|
|
18
|
+
|
|
19
|
+
type YmdValue = TypeOf<typeof ymdValue>;
|
|
20
|
+
|
|
21
|
+
expectType<YmdValue, number>('=');
|
|
22
|
+
|
|
23
|
+
expectType<typeof ymdValue.defaultValue, YmdValue>('=');
|
|
24
|
+
|
|
25
|
+
describe('is', () => {
|
|
26
|
+
test('truthy case', () => {
|
|
27
|
+
const x: unknown = 2000;
|
|
28
|
+
|
|
29
|
+
if (ymdValue.is(x)) {
|
|
30
|
+
expectType<typeof x, number>('=');
|
|
31
|
+
} else {
|
|
32
|
+
expectType<typeof x, unknown>('=');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
expect(ymdValue.is(x)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('falsy case', () => {
|
|
39
|
+
const x: unknown = 'not-a-number';
|
|
40
|
+
|
|
41
|
+
if (ymdValue.is(x)) {
|
|
42
|
+
expectType<typeof x, number>('=');
|
|
43
|
+
} else {
|
|
44
|
+
expectType<typeof x, unknown>('=');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
expect(ymdValue.is(x)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('validate', () => {
|
|
52
|
+
test('truthy case', () => {
|
|
53
|
+
const x: unknown = 2000;
|
|
54
|
+
|
|
55
|
+
const result = ymdValue.validate(x);
|
|
56
|
+
expect(Result.isOk(result)).toBe(true);
|
|
57
|
+
|
|
58
|
+
if (Result.isOk(result)) {
|
|
59
|
+
expectType<typeof result.value, YmdValue>('=');
|
|
60
|
+
expect(result.value).toBe(2000);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('validate returns input as-is for OK cases', () => {
|
|
65
|
+
const input = 2000;
|
|
66
|
+
const result = ymdValue.validate(input);
|
|
67
|
+
expect(Result.isOk(result)).toBe(true);
|
|
68
|
+
if (Result.isOk(result)) {
|
|
69
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('falsy case', () => {
|
|
74
|
+
const x: unknown = 'not-a-number';
|
|
75
|
+
|
|
76
|
+
const result = ymdValue.validate(x);
|
|
77
|
+
expect(Result.isErr(result)).toBe(true);
|
|
78
|
+
|
|
79
|
+
if (Result.isErr(result)) {
|
|
80
|
+
expect(result.value).toStrictEqual([
|
|
81
|
+
{
|
|
82
|
+
path: [],
|
|
83
|
+
actualValue: 'not-a-number',
|
|
84
|
+
expectedType:
|
|
85
|
+
'ValueOf<{ year: number, month: number, date: number }>',
|
|
86
|
+
typeName: 'ValueOf<{ year: number, month: number, date: number }>',
|
|
87
|
+
message:
|
|
88
|
+
'The type of value is expected to be one of the elements contained in { number, number, number }',
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
expect(validationErrorsToMessages(result.value)).toStrictEqual([
|
|
92
|
+
'The type of value is expected to be one of the elements contained in { number, number, number }',
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('fill', () => {
|
|
99
|
+
test('from external value', () => {
|
|
100
|
+
const x: unknown = 'not-a-number';
|
|
101
|
+
|
|
102
|
+
expect(ymdValue.fill(x)).toBe(1900);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('from valid number', () => {
|
|
106
|
+
const x = 2000;
|
|
107
|
+
|
|
108
|
+
expect(ymdValue.fill(x)).toBe(2000);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('mixed types', () => {
|
|
113
|
+
const mixedValue = valueof(
|
|
114
|
+
record({
|
|
115
|
+
name: string('John'),
|
|
116
|
+
age: number(25),
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expectType<typeof mixedValue, Type<string | number>>('=');
|
|
121
|
+
|
|
122
|
+
type MixedValue = TypeOf<typeof mixedValue>;
|
|
123
|
+
|
|
124
|
+
expectType<MixedValue, string | number>('=');
|
|
125
|
+
|
|
126
|
+
test('accepts string', () => {
|
|
127
|
+
const x: unknown = 'Alice';
|
|
128
|
+
expect(mixedValue.is(x)).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('accepts number', () => {
|
|
132
|
+
const x: unknown = 30;
|
|
133
|
+
expect(mixedValue.is(x)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('rejects boolean', () => {
|
|
137
|
+
const x: unknown = true;
|
|
138
|
+
expect(mixedValue.is(x)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('validate mixed values', () => {
|
|
142
|
+
const stringResult = mixedValue.validate('Alice');
|
|
143
|
+
expect(Result.isOk(stringResult)).toBe(true);
|
|
144
|
+
if (Result.isOk(stringResult)) {
|
|
145
|
+
expect(stringResult.value).toBe('Alice');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const numberResult = mixedValue.validate(30);
|
|
149
|
+
expect(Result.isOk(numberResult)).toBe(true);
|
|
150
|
+
if (Result.isOk(numberResult)) {
|
|
151
|
+
expect(numberResult.value).toBe(30);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('fill from invalid value uses first type default', () => {
|
|
156
|
+
expect(mixedValue.fill(true)).toBe('John');
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('same type values', () => {
|
|
161
|
+
const sameTypeValue = valueof(
|
|
162
|
+
record({
|
|
163
|
+
first: string('hello'),
|
|
164
|
+
second: string('world'),
|
|
165
|
+
}),
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
expectType<typeof sameTypeValue, Type<string>>('=');
|
|
169
|
+
|
|
170
|
+
test('accepts any string', () => {
|
|
171
|
+
expect(sameTypeValue.is('test')).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('rejects non-string', () => {
|
|
175
|
+
expect(sameTypeValue.is(123)).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
});
|