Skip to content

Commit

Permalink
[New] add types
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Jan 15, 2024
1 parent df6c7eb commit bd92413
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,6 @@ package-lock.json
yarn.lock

.npmignore

*.d.ts
*.d.ts.map
20 changes: 14 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,34 @@ var $slice = callBound('Array.prototype.slice');
var hasSymbols = require('has-symbols/shams')();
var isConcatSpreadable = hasSymbols && Symbol.isConcatSpreadable;

var empty = [];
/** @type {never[]} */ var empty = [];
var $concatApply = isConcatSpreadable ? callBind.apply($concat, empty) : null;
var $concatCall = isConcatSpreadable ? null : callBind($concat, empty);

var isArray = isConcatSpreadable ? require('isarray') : null;

module.exports = isConcatSpreadable
/** @type {typeof Array.prototype.concat} */
var safeConcat = isConcatSpreadable
// eslint-disable-next-line no-unused-vars
? function safeArrayConcat(item) {
for (var i = 0; i < arguments.length; i += 1) {
var arg = arguments[i];
/** @type {typeof item} */ var arg = arguments[i];
// @ts-expect-error ts(2538) see https://github.com/microsoft/TypeScript/issues/9998#issuecomment-1890787975; works if `const`
if (arg && typeof arg === 'object' && typeof arg[isConcatSpreadable] === 'boolean') {
// @ts-expect-error ts(7015) TS doesn't yet support Symbol indexing
if (!empty[isConcatSpreadable]) {
// @ts-expect-error ts(7015) TS doesn't yet support Symbol indexing
empty[isConcatSpreadable] = true;
}
var arr = isArray(arg) ? $slice(arg) : [arg];
// @ts-expect-error ts(2721) ts(18047) not sure why TS can't figure out this can't be nul
/** @type {T[]} */ var arr = isArray(arg) ? $slice(arg) : [arg];
// @ts-expect-error ts(7015) TS can't handle expandos on an array
arr[isConcatSpreadable] = true; // shadow the property. TODO: use [[Define]]
arguments[i] = arr;
}
}
// @ts-expect-error ts(2345) TS doesn't understand that apply can take an arguments object
return $concatApply(arguments);
}
: $concatCall;
: callBind($concat, empty);

module.exports = safeConcat;
19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
},
"sideEffects": false,
"scripts": {
"prepack": "npmignore --auto --commentLines=autogenerated",
"prepack": "npmignore --auto --commentLines=autogenerated && npm run emit",
"version": "auto-changelog && git add CHANGELOG.md",
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"",
"prelint": "npm run tsc",
"lint": "eslint --ext=js,mjs .",
"preemit": "rm -f *.ts *.ts.map test/*.ts test/*.ts.map",
"emit": "npm run tsc -- --noEmit false --emitDeclarationOnly",
"tsc": "tsc -p .",
"postlint": "evalmd README.md",
"prepublish": "not-in-publish || npm run prepublishOnly",
"prepublishOnly": "safe-publish-latest",
Expand Down Expand Up @@ -43,6 +47,12 @@
"homepage": "https://github.com/ljharb/safe-array-concat#readme",
"devDependencies": {
"@ljharb/eslint-config": "^21.1.0",
"@types/call-bind": "^1.0.5",
"@types/get-intrinsic": "^1.2.2",
"@types/has-symbols": "^1.0.2",
"@types/isarray": "^2.0.2",
"@types/mock-property": "^1.0.2",
"@types/tape": "^5.6.4",
"aud": "^2.0.4",
"auto-changelog": "^2.4.0",
"eslint": "=8.8.0",
Expand All @@ -53,7 +63,8 @@
"nyc": "^10.3.2",
"safe-publish-latest": "^2.0.0",
"set-function-length": "^1.2.0",
"tape": "^5.7.3"
"tape": "^5.7.3",
"typescript": "^5.4.0-dev.20240114"
},
"dependencies": {
"call-bind": "^1.0.5",
Expand All @@ -71,7 +82,9 @@
},
"publishConfig": {
"ignore": [
".github/workflows"
".github/workflows",
"!*.d.ts",
"!*.d.ts.map"
]
},
"engines": {
Expand Down
45 changes: 25 additions & 20 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ test('safe-array-concat', function (t) {
t.equal(
safeConcat.length,
boundFnsHaveConfigurableLengths ? 1 : 0,
'has a length of ' + (boundFnsHaveConfigurableLengths ? 1 : '0 (function lengths are not configurable)'),
'length is as expected'
'has a length of ' + (boundFnsHaveConfigurableLengths ? 1 : '0 (function lengths are not configurable)')
);

t.deepEqual(
Expand Down Expand Up @@ -48,7 +47,9 @@ test('safe-array-concat', function (t) {

t.test('has Symbol.species', { skip: !species }, function (st) {
var speciesArr = [1, 2];
// @ts-expect-error ts(2740) TS's `constructor` type requires a function
speciesArr.constructor = {};
// @ts-expect-error ts(2538) TS can't type narrow from tape's `skip`
speciesArr.constructor[species] = function Species() {
return { args: arguments };
};
Expand All @@ -63,24 +64,28 @@ test('safe-array-concat', function (t) {
});

t.test('has isConcatSpreadable', { skip: !isConcatSpreadable }, function (st) {
st.teardown(mockProperty(String.prototype, isConcatSpreadable, { value: true }));

var nonSpreadable = [1, 2];
nonSpreadable[isConcatSpreadable] = false;

st.deepEqual(
safeConcat(nonSpreadable, 3, 4, 'foo', Object('bar')),
[1, 2, 3, 4, 'foo', Object('bar')],
'a non-concat-spreadable array is spreaded, and a concat-spreadable String is not spreaded'
);

st.teardown(mockProperty(Array.prototype, isConcatSpreadable, { value: false }));

st.deepEqual(
safeConcat([1, 2], 3, 4, 'foo', Object('bar')),
[1, 2, 3, 4, 'foo', Object('bar')],
'all arrays marked non-concat-spreadable are still spreaded, and a concat-spreadable String is not spreaded'
);
// TS can't type narrow from tape's `skip`
if (isConcatSpreadable) {
st.teardown(mockProperty(String.prototype, isConcatSpreadable, { value: true }));

var nonSpreadable = [1, 2];
// @ts-expect-error ts(7015) TS can't handle expandos on an array
nonSpreadable[isConcatSpreadable] = false;

st.deepEqual(
safeConcat(nonSpreadable, 3, 4, 'foo', Object('bar')),
[1, 2, 3, 4, 'foo', Object('bar')],
'a non-concat-spreadable array is spreaded, and a concat-spreadable String is not spreaded'
);

st.teardown(mockProperty(Array.prototype, isConcatSpreadable, { value: false }));

st.deepEqual(
safeConcat([1, 2], 3, 4, 'foo', Object('bar')),
[1, 2, 3, 4, 'foo', Object('bar')],
'all arrays marked non-concat-spreadable are still spreaded, and a concat-spreadable String is not spreaded'
);
}

st.end();
});
Expand Down
49 changes: 49 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */

/* Projects */

/* Language and Environment */
"target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
"useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */

/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": ["types"], /* Specify multiple folders that act like `./node_modules/@types`. */
"resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */

/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
"checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
"maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */

/* Emit */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declarationMap": true, /* Create sourcemaps for d.ts files. */
"noEmit": true, /* Disable emitting files from a compilation. */

/* Interop Constraints */
"allowSyntheticDefaultImports": true, /* Allow `import x from y` when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */

/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */

/* Completeness */
// "skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"exclude": [
"coverage",
],
}

0 comments on commit bd92413

Please sign in to comment.