Skip to content

Commit 39066a4

Browse files
committed
[New] add types
1 parent 6fd4097 commit 39066a4

File tree

7 files changed

+50
-8
lines changed

7 files changed

+50
-8
lines changed

.editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ end_of_line = lf
77
charset = utf-8
88
trim_trailing_whitespace = true
99
insert_final_newline = true
10-
max_line_length = 150
10+
max_line_length = 200
1111

1212
[CHANGELOG.md]
1313
indent_style = space

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"extends": "@ljharb",
55

66
"rules": {
7+
"func-style": 0,
78
"id-length": [1],
89
},
910
}

index.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare function isRegex(value: unknown): value is RegExp;
2+
3+
export = isRegex;

index.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ var hasToStringTag = require('has-tostringtag/shams')();
55
var hasOwn = require('hasown');
66
var gOPD = require('gopd');
77

8+
/** @type {import('.')} */
89
var fn;
10+
911
if (hasToStringTag) {
12+
/** @type {(receiver: ThisParameterType<typeof RegExp.prototype.exec>, ...args: Parameters<typeof RegExp.prototype.exec>) => ReturnType<typeof RegExp.prototype.exec>} */
1013
var $exec = callBound('RegExp.prototype.exec');
14+
/** @type {object} */
1115
var isRegexMarker = {};
1216

1317
var throwRegexMarker = function () {
1418
throw isRegexMarker;
1519
};
20+
/** @type {{ toString(): never, valueOf(): never, [Symbol.toPrimitive]?(): never }} */
1621
var badStringifier = {
1722
toString: throwRegexMarker,
1823
valueOf: throwRegexMarker
@@ -22,28 +27,35 @@ if (hasToStringTag) {
2227
badStringifier[Symbol.toPrimitive] = throwRegexMarker;
2328
}
2429

30+
/** @type {import('.')} */
31+
// @ts-expect-error TS can't figure out that the $exec call always throws
2532
// eslint-disable-next-line consistent-return
2633
fn = function isRegex(value) {
2734
if (!value || typeof value !== 'object') {
2835
return false;
2936
}
3037

31-
var descriptor = gOPD(value, 'lastIndex');
38+
// eslint-disable-next-line no-extra-parens
39+
var descriptor = /** @type {NonNullable<typeof gOPD>} */ (gOPD)(/** @type {{ lastIndex?: unknown }} */ (value), 'lastIndex');
3240
var hasLastIndexDataProperty = descriptor && hasOwn(descriptor, 'value');
3341
if (!hasLastIndexDataProperty) {
3442
return false;
3543
}
3644

3745
try {
38-
$exec(value, badStringifier);
46+
// eslint-disable-next-line no-extra-parens
47+
$exec(value, /** @type {string} */ (/** @type {unknown} */ (badStringifier)));
3948
} catch (e) {
4049
return e === isRegexMarker;
4150
}
4251
};
4352
} else {
53+
/** @type {(receiver: ThisParameterType<typeof Object.prototype.toString>, ...args: Parameters<typeof Object.prototype.toString>) => ReturnType<typeof Object.prototype.toString>} */
4454
var $toString = callBound('Object.prototype.toString');
55+
/** @const @type {'[object RegExp]'} */
4556
var regexClass = '[object RegExp]';
4657

58+
/** @type {import('.')} */
4759
fn = function isRegex(value) {
4860
// In older browsers, typeof regex incorrectly returns 'function'
4961
if (!value || (typeof value !== 'object' && typeof value !== 'function')) {

package.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"posttest": "npx npm@'>=10.2' audit --production",
2121
"prelint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
2222
"lint": "eslint --ext=js,mjs .",
23+
"postlint": "tsc -p . && attw -P",
2324
"version": "auto-changelog && git add CHANGELOG.md",
2425
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
2526
},
@@ -46,7 +47,13 @@
4647
"hasown": "^2.0.2"
4748
},
4849
"devDependencies": {
50+
"@arethetypeswrong/cli": "^0.17.0",
4951
"@ljharb/eslint-config": "^21.1.1",
52+
"@ljharb/tsconfig": "^0.2.0",
53+
"@types/call-bind": "^1.0.5",
54+
"@types/core-js": "^2.5.8",
55+
"@types/for-each": "^0.3.3",
56+
"@types/tape": "^5.6.5",
5057
"auto-changelog": "^2.5.0",
5158
"core-js": "^3.39.0",
5259
"eclint": "^2.8.1",
@@ -57,7 +64,8 @@
5764
"npmignore": "^0.3.1",
5865
"nyc": "^10.3.2",
5966
"safe-publish-latest": "^2.0.0",
60-
"tape": "^5.9.0"
67+
"tape": "^5.9.0",
68+
"typescript": "^5.8.0-dev.20241129"
6169
},
6270
"testling": {
6371
"files": "test/index.js",

test/index.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ var test = require('tape');
66
var isRegex = require('..');
77

88
test('not regexes', function (t) {
9+
// @ts-expect-error
910
t.notOk(isRegex(), 'undefined is not regex');
1011
t.notOk(isRegex(null), 'null is not regex');
1112
t.notOk(isRegex(false), 'false is not regex');
@@ -20,6 +21,7 @@ test('not regexes', function (t) {
2021

2122
test('@@toStringTag', { skip: !hasToStringTag }, function (t) {
2223
var regex = /a/g;
24+
/** @type {{ toString(): string, valueOf(): RegExp, [Symbol.toStringTag]?: string}} */
2325
var fakeRegex = {
2426
toString: function () { return String(regex); },
2527
valueOf: function () { return regex; }
@@ -39,6 +41,7 @@ test('does not mutate regexes', function (t) {
3941
t.test('lastIndex is a marker object', function (st) {
4042
var regex = /a/;
4143
var marker = {};
44+
// @ts-expect-error
4245
regex.lastIndex = marker;
4346
st.equal(regex.lastIndex, marker, 'lastIndex is the marker object');
4447
st.ok(isRegex(regex), 'is regex');
@@ -59,11 +62,14 @@ test('does not mutate regexes', function (t) {
5962
});
6063

6164
test('does not perform operations observable to Proxies', { skip: typeof Proxy !== 'function' }, function (t) {
62-
var Handler = function () {
65+
/** @constructor */
66+
function Handler() {
67+
/** @type (keyof Reflect)[]} */
6368
this.trapCalls = [];
64-
};
69+
}
6570

66-
forEach([
71+
// eslint-disable-next-line no-extra-parens
72+
forEach(/** @const @type {(keyof Reflect)[]} */ ([
6773
'defineProperty',
6874
'deleteProperty',
6975
'get',
@@ -75,15 +81,17 @@ test('does not perform operations observable to Proxies', { skip: typeof Proxy !
7581
'preventExtensions',
7682
'set',
7783
'setPrototypeOf'
78-
], function (trapName) {
84+
]), function (trapName) {
7985
Handler.prototype[trapName] = function () {
8086
this.trapCalls.push(trapName);
87+
// @ts-expect-error TODO: not sure why this is erroring
8188
return Reflect[trapName].apply(Reflect, arguments);
8289
};
8390
});
8491

8592
t.test('proxy of object', function (st) {
8693
var handler = new Handler();
94+
// @ts-expect-error Proxy handlers can be any object
8795
var proxy = new Proxy({ lastIndex: 0 }, handler);
8896

8997
st.equal(isRegex(proxy), false, 'proxy of plain object is not regex');
@@ -97,6 +105,7 @@ test('does not perform operations observable to Proxies', { skip: typeof Proxy !
97105

98106
t.test('proxy of RegExp instance', function (st) {
99107
var handler = new Handler();
108+
// @ts-expect-error Proxy handlers can be any object
100109
var proxy = new Proxy(/a/, handler);
101110

102111
st.equal(isRegex(proxy), false, 'proxy of RegExp instance is not regex');

tsconfig.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "@ljharb/tsconfig",
3+
"compilerOptions": {
4+
"target": "ES2021",
5+
},
6+
"exclude": [
7+
"coverage"
8+
]
9+
}

0 commit comments

Comments
 (0)