Skip to content

Commit a4b91de

Browse files
authored
Merge pull request #67 from lambdalisue/ref-record
💥 Rename `isRecord/isRecordOf/isRecordLike/isRecordLikeOf`
2 parents 5f92c85 + 07030f0 commit a4b91de

File tree

6 files changed

+175
-40
lines changed

6 files changed

+175
-40
lines changed

is/__snapshots__/factory_test.ts.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"
108108
109109
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyOf(isUniformTupleOf(3, (anonymous)))"`;
110110
111+
snapshot[`isRecordObjectOf<T> > returns properly named function 1`] = `"isRecordObjectOf(isNumber, undefined)"`;
112+
113+
snapshot[`isRecordObjectOf<T> > returns properly named function 2`] = `"isRecordObjectOf((anonymous), undefined)"`;
114+
115+
snapshot[`isRecordObjectOf<T, K> > returns properly named function 1`] = `"isRecordObjectOf(isNumber, isString)"`;
116+
117+
snapshot[`isRecordObjectOf<T, K> > returns properly named function 2`] = `"isRecordObjectOf((anonymous), isString)"`;
118+
111119
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber, undefined)"`;
112120
113121
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous), undefined)"`;

is/annotation_test.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
isFunction,
1717
isNull,
1818
isNumber,
19-
isRecord,
19+
isRecordObject,
2020
isSet,
2121
isString,
2222
isSymbol,
@@ -121,8 +121,8 @@ Deno.test("isOptionalOf<T>", async (t) => {
121121
validExamples: ["set", "undefined"],
122122
});
123123
});
124-
await t.step("with isRecord", async (t) => {
125-
await testWithExamples(t, isOptionalOf(isRecord), {
124+
await t.step("with isRecordObject", async (t) => {
125+
await testWithExamples(t, isOptionalOf(isRecordObject), {
126126
validExamples: ["record", "undefined"],
127127
});
128128
});
@@ -208,10 +208,14 @@ Deno.test("isUnwrapOptionalOf<T>", async (t) => {
208208
validExamples: ["set"],
209209
});
210210
});
211-
await t.step("with isRecord", async (t) => {
212-
await testWithExamples(t, isUnwrapOptionalOf(isOptionalOf(isRecord)), {
213-
validExamples: ["record"],
214-
});
211+
await t.step("with isRecordObject", async (t) => {
212+
await testWithExamples(
213+
t,
214+
isUnwrapOptionalOf(isOptionalOf(isRecordObject)),
215+
{
216+
validExamples: ["record"],
217+
},
218+
);
215219
});
216220
await t.step("with isFunction", async (t) => {
217221
await testWithExamples(t, isUnwrapOptionalOf(isOptionalOf(isFunction)), {

is/core.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export function isSet(x: unknown): x is Set<unknown> {
140140
}
141141

142142
/**
143-
* Return `true` if the type of `x` is `Record<PropertyKey, unknown>`.
143+
* Return `true` if the type of `x` is an object instance that satisfies `Record<PropertyKey, unknown>`.
144144
*
145145
* Note that this function check if the `x` is an instance of `Object`.
146146
* Use `isRecordLike` instead if you want to check if the `x` satisfies the `Record<PropertyKey, unknown>` type.
@@ -149,39 +149,56 @@ export function isSet(x: unknown): x is Set<unknown> {
149149
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
150150
*
151151
* const a: unknown = {"a": 0, "b": 1};
152-
* if (is.Record(a)) {
152+
* if (is.RecordObject(a)) {
153153
* // a is narrowed to Record<PropertyKey, unknown>
154154
* const _: Record<PropertyKey, unknown> = a;
155155
* }
156+
*
157+
* const b: unknown = new Set();
158+
* if (is.RecordObject(b)) {
159+
* // b is not a raw object, so it is not narrowed
160+
* }
156161
* ```
157162
*/
158-
export function isRecord(
163+
export function isRecordObject(
159164
x: unknown,
160165
): x is Record<PropertyKey, unknown> {
161166
return x != null && typeof x === "object" && x.constructor === Object;
162167
}
163168

164169
/**
165-
* Return `true` if the type of `x` is like `Record<PropertyKey, unknown>`.
170+
* Return `true` if the type of `x` satisfies `Record<PropertyKey, unknown>`.
166171
*
167172
* Note that this function returns `true` for ambiguous instances like `Set`, `Map`, `Date`, `Promise`, etc.
168173
*
169174
* ```ts
170175
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
171176
*
172177
* const a: unknown = {"a": 0, "b": 1};
173-
* if (is.RecordLike(a)) {
178+
* if (is.Record(a)) {
174179
* // a is narrowed to Record<PropertyKey, unknown>
175180
* const _: Record<PropertyKey, unknown> = a;
176181
* }
177182
*
178-
* const b: unknown = new Date();
179-
* if (is.RecordLike(b)) {
180-
* // a is narrowed to Record<PropertyKey, unknown>
183+
* const b: unknown = new Set();
184+
* if (is.Record(b)) {
185+
* // b is narrowed to Record<PropertyKey, unknown>
181186
* const _: Record<PropertyKey, unknown> = b;
182187
* }
183188
* ```
184189
*/
190+
export function isRecord(
191+
x: unknown,
192+
): x is Record<PropertyKey, unknown> {
193+
return x != null && !Array.isArray(x) && typeof x === "object";
194+
}
195+
196+
/**
197+
* Return `true` if the type of `x` is like `Record<PropertyKey, unknown>`.
198+
*
199+
* @deprecated Use `is.Record` instead.
200+
* ```
201+
*/
185202
export function isRecordLike(
186203
x: unknown,
187204
): x is Record<PropertyKey, unknown> {
@@ -376,6 +393,7 @@ export default {
376393
Primitive: isPrimitive,
377394
Record: isRecord,
378395
RecordLike: isRecordLike,
396+
RecordObject: isRecordObject,
379397
Set: isSet,
380398
String: isString,
381399
Symbol: isSymbol,

is/core_test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import is, {
1818
isPrimitive,
1919
isRecord,
2020
isRecordLike,
21+
isRecordObject,
2122
isSet,
2223
isString,
2324
isSymbol,
@@ -142,9 +143,15 @@ Deno.test("isSet", async (t) => {
142143
await testWithExamples(t, isSet, { validExamples: ["set"] });
143144
});
144145

146+
Deno.test("isRecordObject", async (t) => {
147+
await testWithExamples(t, isRecordObject, {
148+
validExamples: ["record"],
149+
});
150+
});
151+
145152
Deno.test("isRecord", async (t) => {
146153
await testWithExamples(t, isRecord, {
147-
validExamples: ["record"],
154+
validExamples: ["record", "date", "promise", "set", "map"],
148155
});
149156
});
150157

is/factory.ts

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
isArray,
77
isMap,
88
isRecord,
9-
isRecordLike,
9+
isRecordObject,
1010
isSet,
1111
type Primitive,
1212
} from "./core.ts";
@@ -368,17 +368,17 @@ export function isReadonlyUniformTupleOf<T, N extends number>(
368368
}
369369

370370
/**
371-
* Return a type predicate function that returns `true` if the type of `x` is `Record<K, T>`.
371+
* Return a type predicate function that returns `true` if the type of `x` is an Object instance that satisfies `Record<K, T>`.
372372
*
373373
* To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
374374
*
375375
* Note that this function check if the `x` is an instance of `Object`.
376-
* Use `isRecordLikeOf` instead if you want to check if the `x` satisfies the `Record<K, T>` type.
376+
* Use `isRecordOf` instead if you want to check if the `x` satisfies the `Record<K, T>` type.
377377
*
378378
* ```ts
379379
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
380380
*
381-
* const isMyType = is.RecordOf(is.Number);
381+
* const isMyType = is.RecordObjectOf(is.Number);
382382
* const a: unknown = {"a": 0, "b": 1};
383383
* if (isMyType(a)) {
384384
* // a is narrowed to Record<PropertyKey, number>
@@ -391,45 +391,45 @@ export function isReadonlyUniformTupleOf<T, N extends number>(
391391
* ```ts
392392
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
393393
*
394-
* const isMyType = is.RecordOf(is.Number, is.String);
394+
* const isMyType = is.RecordObjectOf(is.Number, is.String);
395395
* const a: unknown = {"a": 0, "b": 1};
396396
* if (isMyType(a)) {
397397
* // a is narrowed to Record<string, number>
398398
* const _: Record<string, number> = a;
399399
* }
400400
* ```
401401
*/
402-
export function isRecordOf<T, K extends PropertyKey = PropertyKey>(
402+
export function isRecordObjectOf<T, K extends PropertyKey = PropertyKey>(
403403
pred: Predicate<T>,
404404
predKey?: Predicate<K>,
405-
): Predicate<Record<K, T>> & WithMetadata<IsRecordOfMetadata> {
405+
): Predicate<Record<K, T>> & WithMetadata<IsRecordObjectOfMetadata> {
406406
return setPredicateFactoryMetadata(
407407
(x: unknown): x is Record<K, T> => {
408-
if (!isRecord(x)) return false;
408+
if (!isRecordObject(x)) return false;
409409
for (const k in x) {
410410
if (!pred(x[k])) return false;
411411
if (predKey && !predKey(k)) return false;
412412
}
413413
return true;
414414
},
415-
{ name: "isRecordOf", args: [pred, predKey] },
415+
{ name: "isRecordObjectOf", args: [pred, predKey] },
416416
);
417417
}
418418

419-
type IsRecordOfMetadata = {
420-
name: "isRecordOf";
421-
args: Parameters<typeof isRecordOf>;
419+
type IsRecordObjectOfMetadata = {
420+
name: "isRecordObjectOf";
421+
args: Parameters<typeof isRecordObjectOf>;
422422
};
423423

424424
/**
425-
* Return a type predicate function that returns `true` if the type of `x` is like `Record<K, T>`.
425+
* Return a type predicate function that returns `true` if the type of `x` satisfies `Record<K, T>`.
426426
*
427427
* To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
428428
*
429429
* ```ts
430430
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
431431
*
432-
* const isMyType = is.RecordLikeOf(is.Number);
432+
* const isMyType = is.RecordOf(is.Number);
433433
* const a: unknown = {"a": 0, "b": 1};
434434
* if (isMyType(a)) {
435435
* // a is narrowed to Record<PropertyKey, number>
@@ -450,23 +450,43 @@ type IsRecordOfMetadata = {
450450
* }
451451
* ```
452452
*/
453-
export function isRecordLikeOf<T, K extends PropertyKey = PropertyKey>(
453+
export function isRecordOf<T, K extends PropertyKey = PropertyKey>(
454454
pred: Predicate<T>,
455455
predKey?: Predicate<K>,
456-
): Predicate<Record<K, T>> & WithMetadata<IsRecordLikeOfMetadata> {
456+
): Predicate<Record<K, T>> & WithMetadata<IsRecordOfMetadata> {
457457
return setPredicateFactoryMetadata(
458458
(x: unknown): x is Record<K, T> => {
459-
if (!isRecordLike(x)) return false;
459+
if (!isRecord(x)) return false;
460460
for (const k in x) {
461461
if (!pred(x[k])) return false;
462462
if (predKey && !predKey(k)) return false;
463463
}
464464
return true;
465465
},
466-
{ name: "isRecordLikeOf", args: [pred, predKey] },
466+
{ name: "isRecordOf", args: [pred, predKey] },
467467
);
468468
}
469469

470+
type IsRecordOfMetadata = {
471+
name: "isRecordOf";
472+
args: Parameters<typeof isRecordOf>;
473+
};
474+
475+
/**
476+
* Return a type predicate function that returns `true` if the type of `x` satisfies `Record<K, T>`.
477+
*
478+
* @deprecated Use `is.RecordOf()` instead
479+
*/
480+
export function isRecordLikeOf<T, K extends PropertyKey = PropertyKey>(
481+
pred: Predicate<T>,
482+
predKey?: Predicate<K>,
483+
): Predicate<Record<K, T>> & WithMetadata<IsRecordLikeOfMetadata> {
484+
return setPredicateFactoryMetadata(isRecordOf(pred, predKey), {
485+
name: "isRecordLikeOf",
486+
args: [pred, predKey],
487+
});
488+
}
489+
470490
type IsRecordLikeOfMetadata = {
471491
name: "isRecordLikeOf";
472492
args: Parameters<typeof isRecordLikeOf>;
@@ -747,6 +767,7 @@ export default {
747767
ReadonlyTupleOf: isReadonlyTupleOf,
748768
ReadonlyUniformTupleOf: isReadonlyUniformTupleOf,
749769
RecordLikeOf: isRecordLikeOf,
770+
RecordObjectOf: isRecordObjectOf,
750771
RecordOf: isRecordOf,
751772
SetOf: isSetOf,
752773
StrictOf: isStrictOf,

0 commit comments

Comments
 (0)