1680158640
Introducing Files, the ultimate file manager app for Windows. With its sleek and intuitive design, navigating through your files has never been easier. Files features tabs for easy switching between different folders, a column view for quick file browsing, and dual pane support for efficient file management. In addition, you can easily create and extract archives with just a few clicks, making file compression and decompression a breeze.
Files also offers advanced features such as file tagging for easy organization, support for QuickLook for previewing files without opening them, and the ability to customize the background color to match your personal style. Whether you're a power user or just looking for a better way to manage your files, Files has everything you need to keep your files organized and easily accessible. With its combination of powerful features and ease of use, Files is the ultimate file management solution for Windows.
git clone https://github.com/files-community/Files
This will create a local copy of the repository.
To build Files for development, open the Files.sln
item in Visual Studio. Right-click on the Files.Package
packaging project in solution explorer and select βSet as Startup itemβ.
In the top pane, select the items which correspond to your desired build mode and the processor architecture of your device like below:
Want to contribute to this project? Let us know with an issue that communicates your intent to create a pull request. Also, view our contributing guidelines to make sure you're up to date on the coding conventions.
Looking for a place to start? Check out the task board, where you can sort tasks by size and priority.
Author: Files-community
Source Code: https://github.com/files-community/Files
License: MIT license
#csharp #windows #productivity #files #xaml #utilities #dotnet
1677888180
Utitilies to convert between CBF and MathProgBase conic format.
dat = readcbfdata("/path/to/instance.cbf") # .cbf.gz extension also accepted
# In MathProgBase format:
c, A, b, con_cones, var_cones, vartypes, sense, objoffset = cbftompb(dat)
# Note: The sense in MathProgBase form is always minimization, and the objective offset is zero.
# If sense == :Max, you should flip the sign of c before handing off to a solver.
# Given the data in MathProgBase format, you can solve it using any corresponding solver which supports the cones present in the problem.
# To use ECOS, for example,
using ECOS
solver = ECOSSolver()
# Now load and solve
m = MathProgBase.ConicModel(ECOSSolver(verbose=0))
MathProgBase.loadproblem!(m, c, A, b, con_cones, var_cones)
# Continuous solvers need not implement setvartype!
if !all(vartypes .== :Cont)
MathProgBase.setvartype!(m, vartypes)
end
MathProgBase.optimize!(m)
# Solution accessible through:
x_sol = MathProgBase.getsolution(m)
objval = MathProgBase.getobjval(m)
# If PSD vars are present, you can use the following utility to extract the solution in CBF form:
scalar_solution, psdvar_solution = ConicBenchmarkUtilities.mpb_sol_to_cbf(dat,x_sol)
newdat = mpbtocbf("example", c, A, b, con_cones, var_cones, vartypes, sense)
writecbfdata("example.cbf",newdat,"# Comment for the CBF header")
Note that because MathProgBase conic format is more general than CBF in specifying the mapping between variables and cones, the order of the variables in the CBF file may not match the original order. No reordering takes place if var_cones
is trivial, i.e., [(:Free,1:N)]
where N
is the total number of variables.
m = JuMP.Model()
@variable(m, x[1:2])
@variable(m, t)
@constraint(m, norm(x) <= t)
ConicBenchmarkUtilities.jump_to_cbf(m, "soctest", "soctest.cbf")
Author: JuliaOpt
Source Code: https://github.com/JuliaOpt/ConicBenchmarkUtilities.jl
License: View license
1675450140
A simple node program for executing commands using an environment from an env file.
npm install env-cmd
or npm install -g env-cmd
Environment file ./.env
# This is a comment
ENV1=THANKS
ENV2=FOR ALL
ENV3=THE FISH
Package.json
{
"scripts": {
"test": "env-cmd mocha -R spec"
}
}
Terminal
./node_modules/.bin/env-cmd node index.js
To use a custom env filename or path, pass the -f
flag. This is a major breaking change from prior versions < 9.0.0
Terminal
./node_modules/.bin/env-cmd -f ./custom/path/.env node index.js
Usage: _ [options] <command> [...args]
Options:
-v, --version output the version number
-e, --environments [env1,env2,...] The rc file environment(s) to use
-f, --file [path] Custom env file path (default path: ./.env)
--fallback Fallback to default env file path, if custom env file path not found
--no-override Do not override existing environment variables
-r, --rc-file [path] Custom rc file path (default path: ./.env-cmdrc(|.js|.json)
--silent Ignore any env-cmd errors and only fail on executed program failure.
--use-shell Execute the command in a new shell with the given environment
--verbose Print helpful debugging information
-x, --expand-envs Replace $var in args and command with environment variables
-h, --help output usage information
.rc
file usageFor more complex projects, a .env-cmdrc
file can be defined in the root directory and supports as many environments as you want. Simply use the -e
flag and provide which environments you wish to use from the .env-cmdrc
file. Using multiple environment names will merge the environment variables together. Later environments overwrite earlier ones in the list if conflicting environment variables are found.
.rc file ./.env-cmdrc
{
"development": {
"ENV1": "Thanks",
"ENV2": "For All"
},
"test": {
"ENV1": "No Thanks",
"ENV3": "!"
},
"production": {
"ENV1": "The Fish"
}
}
Terminal
./node_modules/.bin/env-cmd -e production node index.js
# Or for multiple environments (where `production` vars override `test` vars,
# but both are included)
./node_modules/.bin/env-cmd -e test,production node index.js
--no-override
optionPrevents overriding of existing environment variables on process.env
and within the current environment.
--fallback
file usage optionIf the .env
file does not exist at the provided custom path, then use the default fallback location ./.env
env file instead.
--use-shell
Executes the command within a new shell environment. This is useful if you want to string multiple commands together that share the same environment variables.
Terminal
./node_modules/.bin/env-cmd -f ./test/.env --use-shell "npm run lint && npm test"
EnvCmd supports reading from asynchronous .env
files. Instead of using a .env
file, pass in a .js
file that exports either an object or a Promise
resolving to an object ({ ENV_VAR_NAME: value, ... }
). Asynchronous .rc
files are also supported using .js
file extension and resolving to an object with top level environment names ({ production: { ENV_VAR_NAME: value, ... } }
).
Terminal
./node_modules/.bin/env-cmd -f ./async-file.js node index.js
-x
expands vars in argumentsEnvCmd supports expanding $var
values passed in as arguments to the command. The allows a user to provide arguments to a command that are based on environment variable values at runtime.
NOTE: You must escape the $
character with \
or your terminal might try to auto expand it before passing it to env-cmd
.
Terminal
# $VAR will be expanded into the env value it contains at runtime
./node_modules/.bin/env-cmd -x node index.js --arg=\$VAR
or in package.json
(use \\
to insert a literal backslash)
{
"script": {
"start": "env-cmd -x node index.js --arg=\\$VAR"
}
}
--silent
suppresses env-cmd errorsEnvCmd supports the --silent
flag the suppresses all errors generated by env-cmd
while leaving errors generated by the child process and cli signals still usable. This flag is primarily used to allow env-cmd
to run in environments where the .env
file might not be present, but still execute the child process without failing due to a missing file.
You can find examples of how to use the various options above by visiting the examples repo env-cmd-examples.
These are the currently accepted environment file formats. If any other formats are desired please create an issue.
.env
as key=value
.env.json
Key/value pairs as JSON.env.js
JavaScript file exporting an object
or a Promise
that resolves to an object
.env-cmdrc
as valid json or .env-cmdrc.json
in execution directory with at least one environment { "dev": { "key1": "val1" } }
.env-cmdrc.js
JavaScript file exporting an object
or a Promise
that resolves to an object
that contains at least one environmentThis lib attempts to follow standard bash
path rules. The rules are as followed:
Home Directory = /Users/test
Working Directory = /Users/test/Development/app
Type | Input Path | Expanded Path |
---|---|---|
Absolute | /some/absolute/path.env | /some/absolute/path.env |
Home Directory with ~ | ~/starts/on/homedir/path.env | /Users/test/starts/on/homedir/path.env |
Relative | ./some/relative/path.env or some/relative/path.env | /Users/test/Development/app/some/relative/path.env |
Relative with parent dir | ../some/relative/path.env | /Users/test/Development/some/relative/path.env |
EnvCmd
A function that executes a given command in a new child process with the given environment and options
options
{ object
}command
{ string
}: The command to execute (node
, mocha
, ...)commandArgs
{ string[]
}: List of arguments to pass to the command
(['-R', 'Spec']
)envFile
{ object
}filePath
{ string
}: Custom path to .env file to read from (defaults to: ./.env
)fallback
{ boolean
}: Should fall back to default ./.env
file if custom path does not existrc
{ object
}environments
{ string[]
}: List of environment to read from the .rc
filefilePath
{ string
}: Custom path to the .rc
file (defaults to: ./.env-cmdrc(|.js|.json)
)options
{ object
}expandEnvs
{ boolean
}: Expand $var
values passed to commandArgs
(default: false
)noOverride
{ boolean
}: Prevent .env
file vars from overriding existing process.env
vars (default: false
)silent
{ boolean
}: Ignore any errors thrown by env-cmd, used to ignore missing file errors (default: false
)useShell
{ boolean
}: Runs command inside a new shell instance (default: false
)verbose
{ boolean
}: Prints extra debug logs to console.info
(default: false
)Promise<object>
}: key is env var name and value is the env var valueGetEnvVars
A function that parses environment variables from a .env
or a .rc
file
options
{ object
}envFile
{ object
}filePath
{ string
}: Custom path to .env file to read from (defaults to: ./.env
)fallback
{ boolean
}: Should fall back to default ./.env
file if custom path does not existrc
{ object
}environments
{ string[]
}: List of environment to read from the .rc
filefilePath
{ string
}: Custom path to the .rc
file (defaults to: ./.env-cmdrc(|.js|.json)
)verbose
{ boolean
}: Prints extra debug logs to console.info
(default: false
)Promise<object>
}: key is env var name and value is the env var valueBecause sometimes it is just too cumbersome passing a lot of environment variables to scripts. It is usually just easier to have a file with all the vars in them, especially for development and testing.
π¨Do not commit sensitive environment data to a public git repo! π¨
cross-env
- Cross platform setting of environment scripts
Special thanks to cross-env
for inspiration (uses the same cross-spawn
lib underneath too).
I welcome all pull requests. Please make sure you add appropriate test cases for any features added. Before opening a PR please make sure to run the following scripts:
npm run lint
checks for code errors and format according to ts-standardnpm test
make sure all tests passnpm run test-cover
make sure the coverage has not decreased from current masterAuthor: Toddbluhm
Source Code: https://github.com/toddbluhm/env-cmd
License: MIT license
1669921740
These traditional Linux utilities have been revitalized with modern replacements.
Linux has a good track record for software support. There are about 60 commands in man section 1 of Unix 1st edition, and the majority still work today. Still, progress stops for no one. Thanks to vast global participation in open source, new commands are frequently developed. Sometimes a new command gains popularity, usually because it offers new features, or the same features but with consistent maintenance. Here are ten old commands that have recently been reinvented.
The man page is functional, and it works well for what it does. However, man pages aren't always the most succinct at demonstrating how to use the command you're trying to reference. If you're looking for something a little more to the point, try cheat or tealdeer.
The ifconfig
command provides information about your network interfaces, whether they're physical or virtual.
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.1.2.34 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::f452:f8e1:7f05:7514 prefixlen 64
ether d8:5e:d3:2d:d5:68 txqueuelen 1000 (Ethernet)
[...]
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1360
inet 10.2.3.45 netmask 255.255.254.0 destination 10.2.14.15
inet6 2620:52:4:1109::100e prefixlen 64 scopeid 0x0<global>
unspec 00-00-00-00-00-00-00-00-[...]0-00 txqueuelen 500 (UNSPEC)
[...]
The newer ip
command provides similar information:
$ ip -4 address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 10.1.2.34/24 brd 10.0.1.255 scope global noprefixroute eth0
4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1360 qdisc pfifo_fast state UNKNOWN group default qlen 500
inet 10.2.3.45/23 brd 10.2.15.255 scope global noprefixroute tun0
Package managers tend to be slow to change, and when they do they often work hard to maintain backward compatibility. Both the yum
command and the apt-get
command have had improvements lately. The changes are usually aliased or designed to work in both their old and new syntax:
$ sudo yum install foo
$ sudo dnf install foo
$ sudo apt-get install foo
$ sudo apt install foo
Before there was dnf
there were a variety of utilities for yum
to help users get reports on their packaging system configuration. Most of those extra functions got included by default with dnf
. For instance, repoquery
is a subcommand of dnf
, and it provides a list of all installed packages:
$ sudo dnf repoquery
The pip
command is a package manager for Python. It hasn't been replaced, but the preferred syntax has been updated. The old command:
$ pip install yamllint
The new syntax:
$ python3 -m pip install yamllint
The ls
command hasn't been replaced.
Rather, it hasn't been replaced again.
The ls
command was originally its own binary application, and it's still available as one. Eventually, though, the Bash shell included its own ls
built-in command, which by default overrides any installed ls
command.
Recently, the exa
command has been developed as, depending on your preferences, a better ls
. Read about it in Sudeshna Sur's exa command article, and then try it for yourself.
There's nothing wrong with the du
, which reports on how much disk space is used on your hard drives. It does its job well, but to be fair it's pretty minimal.
If you're looking for a little variety, try the ncdu command or the dust command.
The cat command is, aside from being overused by the best of us, is a simple and direct command. It reads the contents of any number of files, and outputs it to standard input.
Its output is pretty basic, so if you're looking for something with syntax highlighting and flexible output options, try the bat command instead.
Does bat
also replace the tac command? No, don't worry, for now at least tac
is safe in its position as the command that outputs a file in reverse. (Unless, that is, you count sed
.)
The netstat
command has largely been replaced by the ss
command, although of all the commands on this list it's possibly the most hotly debated. The ss
command provides much of the same functionality, but as Jose Vicente Nunez points out in his six deprecated commands article, there are gaps and differences in functionality. Before switching wholesale to ss
, try it and compare it with how you use netstat
now.
I use find
to located files, as an input source for GNU Parallel, and more. I'm pretty familiar with it, but I have to admit that its syntax is a little clunky. The fd
command seeks to improve upon that. For instance, suppose you're looking for a file called example
, but you can't remember what file extension you used. With find
, the syntax might look something like this:
$ find . -name "*example*"
/home/tux/example.adoc
/home/tux/example.sh
With fd
, the syntax is:
$ fd example
/home/tux/example.adoc
/home/tux/example.sh
And suppose you want to grep command to search through the results for the phrase "zombie apocalypse". Using find:
$ find . -name "*example*" -exec grep "zombie apocalypse" {} \;
zombie apocalypse
Using fd
instead:
$ fd txt -x grep zombie
zombie apocalypse
Read more about it in Sudeshna Sur's fd article, and then try it for yourself.
For even more updates to classic commands, download our cheat sheet below.
Original article source at: https://opensource.com/
1668077768
Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types).
Found it useful? Want more updates?
π Now updated to support TypeScript v3.7 π
TypeScript
.dts-jest
# NPM
npm install utility-types
# YARN
yarn add utility-types
TypeScript support
v3.x.x
- TypeScript v3.1+v2.x.x
- TypeScript v2.8.1+v1.x.x
- TypeScript v2.7.2+Utility-Types is an open-source project created by people investing their time for the benefit of our community.
Issues like bug fixes or feature requests can be very quickly resolved when funded through the IssueHunt platform.
I highly recommend adding a bounty to the issue that you're waiting for to attract some contributors willing to work on it.
We are open for contributions. If you're planning to contribute please make sure to read the contributing guide as it can save you from wasting your time: CONTRIBUTING.md
Table of Contents
SetIntersection<A, B>
SetDifference<A, B>
SetComplement<A, A1>
SymmetricDifference<A, B>
Exclude<A, B>
(built-in)Extract<A, B>
(built-in)NonNullable<T>
(built-in)NonUndefined<T>
FunctionKeys<T>
NonFunctionKeys<T>
MutableKeys<T>
ReadonlyKeys<T>
RequiredKeys<T>
OptionalKeys<T>
Optional<T, K>
Partial<T>
(built-in)DeepPartial<T>
Required<T, K>
DeepRequired<T>
Readonly<T>
(built-in)DeepReadonly<T>
Mutable<T>
Pick<T, K>
(built-in)Omit<T, K>
(built-in)PickByValue<T, ValueType>
PickByValueExact<T, ValueType>
OmitByValue<T, ValueType>
OmitByValueExact<T, ValueType>
Intersection<T, U>
Diff<T, U>
Subtract<T, T1>
Overwrite<T, U>
Assign<T, U>
ValuesType<T>
ReturnType<T>
(built-in)InstanceType<T>
(built-in)PromiseType<T>
Unionize<T>
Brand<T, U>
UnionToIntersection<U>
$Keys<T>
$Values<T>
$ReadOnly<T>
$Diff<T, U>
$PropertyType<T, K>
$ElementType<T, K>
$Call<T>
$Shape<T>
$NonMaybeType<T>
Class<T>
mixed
getReturnOfExpression()
- from TS v2.0 it's better to use type-level ReturnType
insteadPrimitive
Type representing primitive types in JavaScript, and thus TypeScript: string | number | bigint | boolean | symbol | null | undefined
You can test for singular of these types with typeof
isPrimitive
This is a TypeScript Typeguard for the Primitive
type.
This can be useful to control the type of a parameter as the program flows. Example:
const consumer = (param: Primitive[] | Primitive): string => {
if (isPrimitive(param)) {
// typeof param === Primitive
return String(param) + ' was Primitive';
}
// typeof param === Primitive[]
const resultArray = param
.map(consumer)
.map(rootString => '\n\t' + rootString);
return resultArray.reduce((comm, newV) => comm + newV, 'this was nested:');
};
Falsy
Type representing falsy values in TypeScript: false | "" | 0 | null | undefined
Except
NaN
which cannot be represented as a type literal
isFalsy
const consumer = (param: Falsy | string): string => {
if (isFalsy(param)) {
// typeof param === Falsy
return String(param) + ' was Falsy';
}
// typeof param === string
return param.toString();
};
Nullish
Type representing nullish values in TypeScript: null | undefined
isNullish
const consumer = (param: Nullish | string): string => {
if (isNullish(param)) {
// typeof param === Nullish
return String(param) + ' was Nullish';
}
// typeof param === string
return param.toString();
};
SetIntersection<A, B>
(same as Extract)Set intersection of given union types A
and B
Usage:
import { SetIntersection } from 'utility-types';
// Expect: "2" | "3"
type ResultSet = SetIntersection<'1' | '2' | '3', '2' | '3' | '4'>;
// Expect: () => void
type ResultSetMixed = SetIntersection<string | number | (() => void), Function>;
SetDifference<A, B>
(same as Exclude)Set difference of given union types A
and B
Usage:
import { SetDifference } from 'utility-types';
// Expect: "1"
type ResultSet = SetDifference<'1' | '2' | '3', '2' | '3' | '4'>;
// Expect: string | number
type ResultSetMixed = SetDifference<string | number | (() => void), Function>;
SetComplement<A, A1>
Set complement of given union types A
and (it's subset) A1
Usage:
import { SetComplement } from 'utility-types';
// Expect: "1"
type ResultSet = SetComplement<'1' | '2' | '3', '2' | '3'>;
SymmetricDifference<A, B>
Set difference of union and intersection of given union types A
and B
Usage:
import { SymmetricDifference } from 'utility-types';
// Expect: "1" | "4"
type ResultSet = SymmetricDifference<'1' | '2' | '3', '2' | '3' | '4'>;
NonNullable<A>
Exclude null
and undefined
from set A
NonUndefined<A>
Exclude undefined
from set A
Exclude<A, B>
Exclude subset B
from set A
Extract<A, B>
Extract subset B
from set A
FunctionKeys<T>
Get union type of keys that are functions in object type T
Usage:
import { FunctionKeys } from 'utility-types';
type MixedProps = { name: string; setName: (name: string) => void };
// Expect: "setName"
type Keys = FunctionKeys<MixedProps>;
NonFunctionKeys<T>
Get union type of keys that are non-functions in object type T
Usage:
import { NonFunctionKeys } from 'utility-types';
type MixedProps = { name: string; setName: (name: string) => void };
// Expect: "name"
type Keys = NonFunctionKeys<MixedProps>;
MutableKeys<T>
Get union type of keys that are mutable (not readonly) in object type T
Alias: WritableKeys<T>
Usage:
import { MutableKeys } from 'utility-types';
type Props = { readonly foo: string; bar: number };
// Expect: "bar"
type Keys = MutableKeys<Props>;
ReadonlyKeys<T>
Get union type of keys that are readonly in object type T
Usage:
import { ReadonlyKeys } from 'utility-types';
type Props = { readonly foo: string; bar: number };
// Expect: "foo"
type Keys = ReadonlyKeys<Props>;
RequiredKeys<T>
Get union type of keys that are required in object type T
Usage:
import { RequiredKeys } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };
// Expect: "req" | "reqUndef"
type Keys = RequiredKeys<Props>;
OptionalKeys<T>
Get union type of keys that are optional in object type T
Usage:
import { OptionalKeys } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };
// Expect: "opt" | "optUndef"
type Keys = OptionalKeys<Props>;
Optional<T, K>
From T
make a set of properties by key K
become optional
Usage:
import { Optional } from 'utility-types';
type Props = { name: string; age: number; visible: boolean; };
// Expect: { name?: string; age?: number; visible?: boolean; }
type Props = Optional<Props>
// Expect: { name: string; age?: number; visible?: boolean; }
type Props = Optional<Props, 'age' | 'visible'>;
Pick<T, K>
(built-in)From T
pick a set of properties by key K
Usage:
type Props = { name: string; age: number; visible: boolean };
// Expect: { age: number; }
type Props = Pick<Props, 'age'>;
PickByValue<T, ValueType>
From T
pick a set of properties by value matching ValueType
. (Credit: Piotr Lewandowski)
Usage:
import { PickByValue } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; };
// Expect: { req: number }
type Props = PickByValue<Props, number>;
// Expect: { req: number; reqUndef: number | undefined; }
type Props = PickByValue<Props, number | undefined>;
PickByValueExact<T, ValueType>
From T
pick a set of properties by value matching exact ValueType
.
Usage:
import { PickByValueExact } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; };
// Expect: { req: number }
type Props = PickByValueExact<Props, number>;
// Expect: { reqUndef: number | undefined; }
type Props = PickByValueExact<Props, number | undefined>;
Omit<T, K>
From T
remove a set of properties by key K
Usage:
import { Omit } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: { name: string; visible: boolean; }
type Props = Omit<Props, 'age'>;
OmitByValue<T, ValueType>
From T
remove a set of properties by value matching ValueType
. (Credit: Piotr Lewandowski)
Usage:
import { OmitByValue } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; };
// Expect: { reqUndef: number | undefined; opt?: string; }
type Props = OmitByValue<Props, number>;
// Expect: { opt?: string; }
type Props = OmitByValue<Props, number | undefined>;
OmitByValueExact<T, ValueType>
From T
remove a set of properties by value matching exact ValueType
.
Usage:
import { OmitByValueExact } from 'utility-types';
type Props = { req: number; reqUndef: number | undefined; opt?: string; };
// Expect: { reqUndef: number | undefined; opt?: string; }
type Props = OmitByValueExact<Props, number>;
// Expect: { req: number; opt?: string }
type Props = OmitByValueExact<Props, number | undefined>;
Intersection<T, U>
From T
pick properties that exist in U
Usage:
import { Intersection } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };
// Expect: { age: number; }
type DuplicatedProps = Intersection<Props, DefaultProps>;
Diff<T, U>
From T
remove properties that exist in U
Usage:
import { Diff } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };
// Expect: { name: string; visible: boolean; }
type RequiredProps = Diff<Props, DefaultProps>;
Subtract<T, T1>
From T
remove properties that exist in T1
(T1
has a subset of the properties of T
)
Usage:
import { Subtract } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };
// Expect: { name: string; visible: boolean; }
type RequiredProps = Subtract<Props, DefaultProps>;
Overwrite<T, U>
From U
overwrite properties to T
Usage:
import { Overwrite } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };
// Expect: { name: string; age: string; visible: boolean; }
type ReplacedProps = Overwrite<Props, NewProps>;
Assign<T, U>
From U
assign properties to T
(just like object assign)
Usage:
import { Assign } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };
// Expect: { name: string; age: string; visible: boolean; other: string; }
type ExtendedProps = Assign<Props, NewProps>;
ValuesType<T>
Get the union type of all the values in an object, tuple, array or array-like type T
.
Usage:
import { ValuesType } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = ValuesType<Props>;
type NumberArray = number[];
// Expect: number
type NumberItems = ValuesType<NumberArray>;
type ReadonlyNumberTuple = readonly [1, 2];
// Expect: 1 | 2
type AnotherNumberUnion = ValuesType<NumberTuple>;
type BinaryArray = Uint8Array;
// Expect: number
type BinaryItems = ValuesType<BinaryArray>;
Partial<T>
Make all properties of object type optional
Required<T, K>
From T
make a set of properties by key K
become required
Usage:
import { Required } from 'utility-types';
type Props = { name?: string; age?: number; visible?: boolean; };
// Expect: { name: string; age: number; visible: boolean; }
type Props = Required<Props>
// Expect: { name?: string; age: number; visible: boolean; }
type Props = Required<Props, 'age' | 'visible'>;
Readonly<T>
Make all properties of object type readonly
Mutable<T>
From T
make all properties become mutable
Alias: Writable<T>
import { Mutable } from 'utility-types';
type Props = {
readonly name: string;
readonly age: number;
readonly visible: boolean;
};
// Expect: { name: string; age: number; visible: boolean; }
Mutable<Props>;
ReturnType<T>
Obtain the return type of a function
InstanceType<T>
Obtain the instance type of a class
Unionize<T>
Disjoin object to form union of objects, each with single property
Usage:
import { Unionize } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: { name: string; } | { age: number; } | { visible: boolean; }
type UnionizedType = Unionize<Props>;
PromiseType<T>
Obtain Promise resolve type
Usage:
import { PromiseType } from 'utility-types';
// Expect: string
type Response = PromiseType<Promise<string>>;
DeepReadonly<T>
Readonly that works for deeply nested structures
Usage:
import { DeepReadonly } from 'utility-types';
type NestedProps = {
first: {
second: {
name: string;
};
};
};
// Expect: {
// readonly first: {
// readonly second: {
// readonly name: string;
// };
// };
// }
type ReadonlyNestedProps = DeepReadonly<NestedProps>;
DeepRequired<T>
Required that works for deeply nested structures
Usage:
import { DeepRequired } from 'utility-types';
type NestedProps = {
first?: {
second?: {
name?: string;
};
};
};
// Expect: {
// first: {
// second: {
// name: string;
// };
// };
// }
type RequiredNestedProps = DeepRequired<NestedProps>;
DeepNonNullable<T>
NonNullable that works for deeply nested structure
Usage:
import { DeepNonNullable } from 'utility-types';
type NestedProps = {
first?: null | {
second?: null | {
name?: string | null | undefined;
};
};
};
// Expect: {
// first: {
// second: {
// name: string;
// };
// };
// }
type RequiredNestedProps = DeepNonNullable<NestedProps>;
DeepPartial<T>
Partial that works for deeply nested structures
Usage:
import { DeepPartial } from 'utility-types';
type NestedProps = {
first: {
second: {
name: string;
};
};
};
// Expect: {
// first?: {
// second?: {
// name?: string;
// };
// };
// }
type PartialNestedProps = DeepPartial<NestedProps>;
Brand<T, U>
Define nominal type of U
based on type of T
. Similar to Opaque types in Flow.
Usage:
import { Brand } from 'utility-types';
type USD = Brand<number, "USD">
type EUR = Brand<number, "EUR">
const tax = 5 as USD;
const usd = 10 as USD;
const eur = 10 as EUR;
function gross(net: USD): USD {
return (net + tax) as USD;
}
gross(usd); // ok
gross(eur); // Type '"EUR"' is not assignable to type '"USD"'.
UnionToIntersection<U>
Get intersection type given union type U
Usage:
import { UnionToIntersection } from 'utility-types';
// Expect: { name: string } & { age: number } & { visible: boolean }
UnionToIntersection<{ name: string } | { age: number } | { visible: boolean }>
$Keys<T>
get the union type of all the keys in an object type T
https://flow.org/en/docs/types/utilities/#toc-keys
Usage:
import { $Keys } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: "name" | "age" | "visible"
type PropsKeys = $Keys<Props>;
$Values<T>
get the union type of all the values in an object type T
https://flow.org/en/docs/types/utilities/#toc-values
Usage:
import { $Values } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = $Values<Props>;
$ReadOnly<T>
get the read-only version of a given object type T
https://flow.org/en/docs/types/utilities/#toc-readonly
Usage:
import { $ReadOnly } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: Readonly<{ name: string; age: number; visible: boolean; }>
type ReadOnlyProps = $ReadOnly<Props>;
$Diff<T, U>
get the set difference of a given object types T
and U
(T \ U
)
https://flow.org/en/docs/types/utilities/#toc-diff
Usage:
import { $Diff } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };
// Expect: { name: string; visible: boolean; }
type RequiredProps = $Diff<Props, DefaultProps>;
$PropertyType<T, K>
get the type of property of an object at a given key K
https://flow.org/en/docs/types/utilities/#toc-propertytype
Usage:
import { $PropertyType } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: string
type NameType = $PropertyType<Props, 'name'>;
type Tuple = [boolean, number];
// Expect: boolean
type A = $PropertyType<Tuple, '0'>;
// Expect: number
type B = $PropertyType<Tuple, '1'>;
$ElementType<T, K>
get the type of elements inside of array, tuple or object of type T
, that matches the given index type K
https://flow.org/en/docs/types/utilities/#toc-elementtype
Usage:
import { $ElementType } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: string
type NameType = $ElementType<Props, 'name'>;
type Tuple = [boolean, number];
// Expect: boolean
type A = $ElementType<Tuple, 0>;
// Expect: number
type B = $ElementType<Tuple, 1>;
type Arr = boolean[];
// Expect: boolean
type ItemsType = $ElementType<Arr, number>;
type Obj = { [key: string]: number };
// Expect: number
type ValuesType = $ElementType<Obj, string>;
$Call<T>
get the return type of a given expression type
https://flow.org/en/docs/types/utilities/#toc-call
The built-in ReturnType
can be used to accomplish the same goal, although it may have some subtle differences.
Usage:
import { $Call } from 'utility-types';
// Common use-case
const add = (amount: number) => ({ type: 'ADD' as 'ADD', payload: amount });
type AddAction = $Call<typeof add>; // { type: 'ADD'; payload: number }
// Examples migrated from Flow docs
type ExtractPropType<T extends { prop: any }> = (arg: T) => T['prop'];
type Obj = { prop: number };
type PropType = $Call<ExtractPropType<Obj>>; // number
// type Nope = $Call<ExtractPropType<{ nope: number }>>; // Error: argument doesn't match `Obj`.
type ExtractReturnType<T extends () => any> = (arg: T) => ReturnType<T>;
type Fn = () => number;
type FnReturnType = $Call<ExtractReturnType<Fn>>; // number
$Shape<T>
Copies the shape of the type supplied, but marks every field optional.
https://flow.org/en/docs/types/utilities/#toc-shape
Usage:
import { $Shape } from 'utility-types';
type Props = { name: string; age: number; visible: boolean };
// Expect: Partial<Props>
type PartialProps = $Shape<Props>;
$NonMaybeType<T>
Converts a type T
to a non-maybe type. In other words, the values of $NonMaybeType<T>
are the values of T
except for null
and undefined
.
https://flow.org/en/docs/types/utilities/#toc-nonmaybe
Usage:
import { $NonMaybeType } from 'utility-types';
type MaybeName = string | null;
// Expect: string
type Name = $NonMaybeType<MaybeName>;
Class<T>
Given a type T representing instances of a class C, the type Class is the type of the class C
https://flow.org/en/docs/types/utilities/#toc-class * Differs from original Flow's util - implements only constructor part and won't include any static members. Additionally classes in Typescript are not treated as nominal
Usage:
import { Class } from 'utility-types';
function makeStore(storeClass: Class<Store>): Store {
return new storeClass();
}
An arbitrary type that could be anything (same as unknown
)
https://flow.org/en/docs/types/mixed
ts-toolbelt
- Higher type safety for TypeScript$mol_type
- Collection of TypeScript meta types for complex logicAuthor: piotrwitek
Source Code: https://github.com/piotrwitek/utility-types
License: MIT license
1667394180
A collection of essential TypeScript types
Many of the types here should have been built-in. You can help by suggesting some of them to the TypeScript project.
Either add this package as a dependency or copy-paste the needed types. No credit required. π
PR welcome for additional commonly needed types and docs improvements. Read the contributing guidelines first.
Help wanted with reviewing proposals and pull requests.
npm install type-fest
Requires TypeScript >=4.7
import type {Except} from 'type-fest';
type Foo = {
unicorn: string;
rainbow: boolean;
};
type FooWithoutRainbow = Except<Foo, 'rainbow'>;
//=> {unicorn: string}
Click the type names for complete docs.
Primitive
- Matches any primitive value.Class
- Matches a class
.Constructor
- Matches a class
constructor.TypedArray
- Matches any typed array, like Uint8Array
or Float64Array
.ObservableLike
- Matches a value that is like an Observable.EmptyObject
- Represents a strictly empty plain object, the {}
value.IsEmptyObject
- Returns a boolean
for whether the type is strictly equal to an empty plain object, the {}
value.Except
- Create a type from an object type without certain keys. This is a stricter version of Omit
.Writable
- Create a type that strips readonly
from all or some of an object's keys. The inverse of Readonly<T>
.Merge
- Merge two types into a new type. Keys of the second type overrides keys of the first type.MergeDeep
- Merge two objects or two arrays/tuples recursively into a new type.MergeExclusive
- Create a type that has mutually exclusive keys.RequireAtLeastOne
- Create a type that requires at least one of the given keys.RequireExactlyOne
- Create a type that requires exactly a single key of the given keys and disallows more.RequireAllOrNone
- Create a type that requires all of the given keys or none of the given keys.OmitIndexSignature
- Omit any index signatures from the given object type, leaving only explicitly defined properties.PickIndexSignature
- Pick only index signatures from the given object type, leaving out all explicitly defined properties.PartialDeep
- Create a deeply optional version of another type. Use Partial<T>
if you only need one level deep.PartialOnUndefinedDeep
- Create a deep version of another type where all keys accepting undefined
type are set to optional.ReadonlyDeep
- Create a deeply immutable version of an object
/Map
/Set
/Array
type. Use Readonly<T>
if you only need one level deep.LiteralUnion
- Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for Microsoft/TypeScript#29729.Opaque
- Create an opaque type.UnwrapOpaque
- Revert an opaque type back to its original type.InvariantOf
- Create an invariant type, which is a type that does not accept supertypes and subtypes.SetOptional
- Create a type that makes the given keys optional.SetRequired
- Create a type that makes the given keys required.SetNonNullable
- Create a type that makes the given keys non-nullable.ValueOf
- Create a union of the given object's values, and optionally specify which keys to get the values from.ConditionalKeys
- Extract keys from a shape where values extend the given Condition
type.ConditionalPick
- Like Pick
except it selects properties from a shape where the values extend the given Condition
type.ConditionalPickDeep
- Like ConditionalPick
except that it selects the properties deeply.ConditionalExcept
- Like Omit
except it removes properties from a shape where the values extend the given Condition
type.UnionToIntersection
- Convert a union type to an intersection type.LiteralToPrimitive
- Convert a literal type to the primitive type it belongs to.Stringified
- Create a type with the keys of the given type changed to string
type.IterableElement
- Get the element type of an Iterable
/AsyncIterable
. For example, an array or a generator.Entry
- Create a type that represents the type of an entry of a collection.Entries
- Create a type that represents the type of the entries of a collection.SetReturnType
- Create a function type with a return type of your choice and the same parameters as the given function type.Simplify
- Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.Get
- Get a deeply-nested property from an object using a key path, like Lodash's .get()
function.StringKeyOf
- Get keys of the given type as strings.Schema
- Create a deep version of another object type where property values are recursively replaced into a given value type.Exact
- Create a type that does not allow extra properties.OptionalKeysOf
- Extract all optional keys from the given type.HasOptionalKeys
- Create a true
/false
type depending on whether the given type has any optional fields.RequiredKeysOf
- Extract all required keys from the given type.HasRequiredKeys
- Create a true
/false
type depending on whether the given type has any required fields.Spread
- Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax.Jsonify
- Transform a type to one that is assignable to the JsonValue
type.JsonPrimitive
- Matches a JSON primitive.JsonObject
- Matches a JSON object.JsonArray
- Matches a JSON array.JsonValue
- Matches any valid JSON value.Promisable
- Create a type that represents either the value or the value wrapped in PromiseLike
.AsyncReturnType
- Unwrap the return type of a function that returns a Promise
.Asyncify
- Create an async version of the given function type.Trim
- Remove leading and trailing spaces from a string.Split
- Represents an array of strings split using a given character or character set.Replace
- Represents a string with some or all matches replaced by a replacement.Includes
- Returns a boolean for whether the given array includes the given item.Join
- Join an array of strings and/or numbers using the given string as a delimiter.LastArrayElement
- Extracts the type of the last element of an array.FixedLengthArray
- Create a type that represents an array of the given type and length.MultidimensionalArray
- Create a type that represents a multidimensional array of the given type and dimensions.MultidimensionalReadonlyArray
- Create a type that represents a multidimensional readonly array of the given type and dimensions.ReadonlyTuple
- Create a type that represents a read-only tuple of the given type and length.TupleToUnion
- Convert a tuple into a union type of its elements.PositiveInfinity
- Matches the hidden Infinity
type.NegativeInfinity
- Matches the hidden -Infinity
type.Finite
- A finite number
.Integer
- A number
that is an integer.Float
- A number
that is not an integer.NegativeFloat
- A negative (-β < x < 0
) number
that is not an integer.Negative
- A negative number
/bigint
(-β < x < 0
)NonNegative
- A non-negative number
/bigint
(0 <= x < β
).NegativeInteger
- A negative (-β < x < 0
) number
that is an integer.NonNegativeInteger
- A non-negative (0 <= x < β
) number
that is an integer.CamelCase
- Convert a string literal to camel-case (fooBar
).CamelCasedProperties
- Convert object properties to camel-case (fooBar
).CamelCasedPropertiesDeep
- Convert object properties to camel-case recursively (fooBar
).KebabCase
- Convert a string literal to kebab-case (foo-bar
).KebabCasedProperties
- Convert a object properties to kebab-case recursively (foo-bar
).KebabCasedPropertiesDeep
- Convert object properties to kebab-case (foo-bar
).PascalCase
- Converts a string literal to pascal-case (FooBar
)PascalCasedProperties
- Converts object properties to pascal-case (FooBar
)PascalCasedPropertiesDeep
- Converts object properties to pascal-case (FooBar
)SnakeCase
- Convert a string literal to snake-case (foo_bar
).SnakeCasedProperties
- Convert object properties to snake-case (foo_bar
).SnakeCasedPropertiesDeep
- Convert object properties to snake-case recursively (foo_bar
).ScreamingSnakeCase
- Convert a string literal to screaming-snake-case (FOO_BAR
).DelimiterCase
- Convert a string literal to a custom string delimiter casing.DelimiterCasedProperties
- Convert object properties to a custom string delimiter casing.DelimiterCasedPropertiesDeep
- Convert object properties to a custom string delimiter casing recursively.PackageJson
- Type for npm's package.json
file. It also includes support for TypeScript Declaration Files and Yarn Workspaces.TsConfigJson
- Type for TypeScript's tsconfig.json
file.If we decline a type addition, we will make sure to document the better solution here.
Diff
and Spread
- The pull request author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.Dictionary
- You only save a few characters (Dictionary<number>
vs Record<string, number>
) from Record
, which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have Map
in JavaScript now.ExtractProperties
and ExtractMethods
- The types violate the single responsibility principle. Instead, refine your types into more granular type hierarchies.Url2Json
- Inferring search parameters from a URL string is a cute idea, but not very useful in practice, since search parameters are usually dynamic and defined separately.Nullish
- The type only saves a couple of characters, not everyone knows what "nullish" means, and I'm also trying to get away from null
.TitleCase
- It's not solving a common need and is a better fit for a separate package.ExtendOr
and ExtendAnd
- The benefits don't outweigh having to learn what they mean.PackageJsonExtras
- There are too many possible configurations that can be put into package.json
. If you would like to extend PackageJson
to support an additional configuration in your project, please see the Extending existing types section below.If you know one of our types by a different name, add it here for discovery.
PartialBy
- See SetOptional
RecordDeep
- See Schema
Mutable
- See Writable
PackageJson
- There are a lot of tools that place extra configurations inside the package.json
file. You can extend PackageJson
to support these additional configurations.
Example
import type {PackageJson as BasePackageJson} from 'type-fest';
import type {Linter} from 'eslint';
type PackageJson = BasePackageJson & {eslintConfig?: Linter.Config};
document.querySelector
and document.querySelectorAll
with a template literal type that matches element types returned from an HTML element query selector.Linter.Config
- Definitions for the ESLint configuration schema.There are many advanced types most users don't know about.
Partial<T>
- Make all properties in T
optional.
Example
interface NodeConfig {
appName: string;
port: number;
}
class NodeAppBuilder {
private configuration: NodeConfig = {
appName: 'NodeApp',
port: 3000
};
private updateConfig<Key extends keyof NodeConfig>(key: Key, value: NodeConfig[Key]) {
this.configuration[key] = value;
}
config(config: Partial<NodeConfig>) {
type NodeConfigKey = keyof NodeConfig;
for (const key of Object.keys(config) as NodeConfigKey[]) {
const updateValue = config[key];
if (updateValue === undefined) {
continue;
}
this.updateConfig(key, updateValue);
}
return this;
}
}
// `Partial<NodeConfig>`` allows us to provide only a part of the
// NodeConfig interface.
new NodeAppBuilder().config({appName: 'ToDoApp'});
Required<T>
- Make all properties in T
required.
Example
interface ContactForm {
email?: string;
message?: string;
}
function submitContactForm(formData: Required<ContactForm>) {
// Send the form data to the server.
}
submitContactForm({
email: 'ex@mple.com',
message: 'Hi! Could you tell me more aboutβ¦',
});
// TypeScript error: missing property 'message'
submitContactForm({
email: 'ex@mple.com',
});
Readonly<T>
- Make all properties in T
readonly.
Example
enum LogLevel {
Off,
Debug,
Error,
Fatal
};
interface LoggerConfig {
name: string;
level: LogLevel;
}
class Logger {
config: Readonly<LoggerConfig>;
constructor({name, level}: LoggerConfig) {
this.config = {name, level};
Object.freeze(this.config);
}
}
const config: LoggerConfig = {
name: 'MyApp',
level: LogLevel.Debug
};
const logger = new Logger(config);
// TypeScript Error: cannot assign to read-only property.
logger.config.level = LogLevel.Error;
// We are able to edit config variable as we please.
config.level = LogLevel.Error;
Pick<T, K>
- From T
, pick a set of properties whose keys are in the union K
.
Example
interface Article {
title: string;
thumbnail: string;
content: string;
}
// Creates new type out of the `Article` interface composed
// from the Articles' two properties: `title` and `thumbnail`.
// `ArticlePreview = {title: string; thumbnail: string}`
type ArticlePreview = Pick<Article, 'title' | 'thumbnail'>;
// Render a list of articles using only title and description.
function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement {
const articles = document.createElement('div');
for (const preview of previews) {
// Append preview to the articles.
}
return articles;
}
const articles = renderArticlePreviews([
{
title: 'TypeScript tutorial!',
thumbnail: '/assets/ts.jpg'
}
]);
Record<K, T>
- Construct a type with a set of properties K
of type T
.
Example
// Positions of employees in our company.
type MemberPosition = 'intern' | 'developer' | 'tech-lead';
// Interface describing properties of a single employee.
interface Employee {
firstName: string;
lastName: string;
yearsOfExperience: number;
}
// Create an object that has all possible `MemberPosition` values set as keys.
// Those keys will store a collection of Employees of the same position.
const team: Record<MemberPosition, Employee[]> = {
intern: [],
developer: [],
'tech-lead': [],
};
// Our team has decided to help John with his dream of becoming Software Developer.
team.intern.push({
firstName: 'John',
lastName: 'Doe',
yearsOfExperience: 0
});
// `Record` forces you to initialize all of the property keys.
// TypeScript Error: "tech-lead" property is missing
const teamEmpty: Record<MemberPosition, null> = {
intern: null,
developer: null,
};
Exclude<T, U>
- Exclude from T
those types that are assignable to U
.
Example
interface ServerConfig {
port: null | string | number;
}
type RequestHandler = (request: Request, response: Response) => void;
// Exclude `null` type from `null | string | number`.
// In case the port is equal to `null`, we will use default value.
function getPortValue(port: Exclude<ServerConfig['port'], null>): number {
if (typeof port === 'string') {
return parseInt(port, 10);
}
return port;
}
function startServer(handler: RequestHandler, config: ServerConfig): void {
const server = require('http').createServer(handler);
const port = config.port === null ? 3000 : getPortValue(config.port);
server.listen(port);
}
Extract<T, U>
- Extract from T
those types that are assignable to U
.
Example
declare function uniqueId(): number;
const ID = Symbol('ID');
interface Person {
[ID]: number;
name: string;
age: number;
}
// Allows changing the person data as long as the property key is of string type.
function changePersonData<
Obj extends Person,
Key extends Extract<keyof Person, string>,
Value extends Obj[Key]
> (obj: Obj, key: Key, value: Value): void {
obj[key] = value;
}
// Tiny Andrew was born.
const andrew = {
[ID]: uniqueId(),
name: 'Andrew',
age: 0,
};
// Cool, we're fine with that.
changePersonData(andrew, 'name', 'Pony');
// Goverment didn't like the fact that you wanted to change your identity.
changePersonData(andrew, ID, uniqueId());
NonNullable<T>
- Exclude null
and undefined
from T
.
ExampleWorks with strictNullChecks
set to true
.
type PortNumber = string | number | null;
/** Part of a class definition that is used to build a server */
class ServerBuilder {
portNumber!: NonNullable<PortNumber>;
port(this: ServerBuilder, port: PortNumber): ServerBuilder {
if (port == null) {
this.portNumber = 8000;
} else {
this.portNumber = port;
}
return this;
}
}
const serverBuilder = new ServerBuilder();
serverBuilder
.port('8000') // portNumber = '8000'
.port(null) // portNumber = 8000
.port(3000); // portNumber = 3000
// TypeScript error
serverBuilder.portNumber = null;
Parameters<T>
- Obtain the parameters of a function type in a tuple.
Example
function shuffle(input: any[]): void {
// Mutate array randomly changing its' elements indexes.
}
function callNTimes<Fn extends (...args: any[]) => any> (func: Fn, callCount: number) {
// Type that represents the type of the received function parameters.
type FunctionParameters = Parameters<Fn>;
return function (...args: FunctionParameters) {
for (let i = 0; i < callCount; i++) {
func(...args);
}
}
}
const shuffleTwice = callNTimes(shuffle, 2);
ConstructorParameters<T>
- Obtain the parameters of a constructor function type in a tuple.
Example
class ArticleModel {
title: string;
content?: string;
constructor(title: string) {
this.title = title;
}
}
class InstanceCache<T extends (new (...args: any[]) => any)> {
private ClassConstructor: T;
private cache: Map<string, InstanceType<T>> = new Map();
constructor (ctr: T) {
this.ClassConstructor = ctr;
}
getInstance (...args: ConstructorParameters<T>): InstanceType<T> {
const hash = this.calculateArgumentsHash(...args);
const existingInstance = this.cache.get(hash);
if (existingInstance !== undefined) {
return existingInstance;
}
return new this.ClassConstructor(...args);
}
private calculateArgumentsHash(...args: any[]): string {
// Calculate hash.
return 'hash';
}
}
const articleCache = new InstanceCache(ArticleModel);
const amazonArticle = articleCache.getInstance('Amazon forests burining!');
ReturnType<T>
- Obtain the return type of a function type.
Example
/** Provides every element of the iterable `iter` into the `callback` function and stores the results in an array. */
function mapIter<
Elem,
Func extends (elem: Elem) => any,
Ret extends ReturnType<Func>
>(iter: Iterable<Elem>, callback: Func): Ret[] {
const mapped: Ret[] = [];
for (const elem of iter) {
mapped.push(callback(elem));
}
return mapped;
}
const setObject: Set<string> = new Set();
const mapObject: Map<number, string> = new Map();
mapIter(setObject, (value: string) => value.indexOf('Foo')); // number[]
mapIter(mapObject, ([key, value]: [number, string]) => {
return key % 2 === 0 ? value : 'Odd';
}); // string[]
InstanceType<T>
- Obtain the instance type of a constructor function type.
Example
class IdleService {
doNothing (): void {}
}
class News {
title: string;
content: string;
constructor(title: string, content: string) {
this.title = title;
this.content = content;
}
}
const instanceCounter: Map<Function, number> = new Map();
interface Constructor {
new(...args: any[]): any;
}
// Keep track how many instances of `Constr` constructor have been created.
function getInstance<
Constr extends Constructor,
Args extends ConstructorParameters<Constr>
>(constructor: Constr, ...args: Args): InstanceType<Constr> {
let count = instanceCounter.get(constructor) || 0;
const instance = new constructor(...args);
instanceCounter.set(constructor, count + 1);
console.log(`Created ${count + 1} instances of ${Constr.name} class`);
return instance;
}
const idleService = getInstance(IdleService);
// Will log: `Created 1 instances of IdleService class`
const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...');
// Will log: `Created 1 instances of News class`
Omit<T, K>
- Constructs a type by picking all properties from T and then removing K.
Example
interface Animal {
imageUrl: string;
species: string;
images: string[];
paragraphs: string[];
}
// Creates new type with all properties of the `Animal` interface
// except 'images' and 'paragraphs' properties. We can use this
// type to render small hover tooltip for a wiki entry list.
type AnimalShortInfo = Omit<Animal, 'images' | 'paragraphs'>;
function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement {
const container = document.createElement('div');
// Internal implementation.
return container;
}
Uppercase<S extends string>
- Transforms every character in a string into uppercase.
Example
type T = Uppercase<'hello'>; // 'HELLO'
type T2 = Uppercase<'foo' | 'bar'>; // 'FOO' | 'BAR'
type T3<S extends string> = Uppercase<`aB${S}`>;
type T4 = T3<'xYz'>; // 'ABXYZ'
type T5 = Uppercase<string>; // string
type T6 = Uppercase<any>; // any
type T7 = Uppercase<never>; // never
type T8 = Uppercase<42>; // Error, type 'number' does not satisfy the constraint 'string'
Lowercase<S extends string>
- Transforms every character in a string into lowercase.
Example
type T = Lowercase<'HELLO'>; // 'hello'
type T2 = Lowercase<'FOO' | 'BAR'>; // 'foo' | 'bar'
type T3<S extends string> = Lowercase<`aB${S}`>;
type T4 = T3<'xYz'>; // 'abxyz'
type T5 = Lowercase<string>; // string
type T6 = Lowercase<any>; // any
type T7 = Lowercase<never>; // never
type T8 = Lowercase<42>; // Error, type 'number' does not satisfy the constraint 'string'
Capitalize<S extends string>
- Transforms the first character in a string into uppercase.
Example
type T = Capitalize<'hello'>; // 'Hello'
type T2 = Capitalize<'foo' | 'bar'>; // 'Foo' | 'Bar'
type T3<S extends string> = Capitalize<`aB${S}`>;
type T4 = T3<'xYz'>; // 'ABxYz'
type T5 = Capitalize<string>; // string
type T6 = Capitalize<any>; // any
type T7 = Capitalize<never>; // never
type T8 = Capitalize<42>; // Error, type 'number' does not satisfy the constraint 'string'
Uncapitalize<S extends string>
- Transforms the first character in a string into lowercase.
type T = Uncapitalize<'Hello'>; // 'hello'
type T2 = Uncapitalize<'Foo' | 'Bar'>; // 'foo' | 'bar'
type T3<S extends string> = Uncapitalize<`AB${S}`>;
type T4 = T3<'xYz'>; // 'aBxYz'
type T5 = Uncapitalize<string>; // string
type T6 = Uncapitalize<any>; // any
type T7 = Uncapitalize<never>; // never
type T8 = Uncapitalize<42>; // Error, type 'number' does not satisfy the constraint 'string'
You can find some examples in the TypeScript docs.
Author: Sindresorhus
Source Code: https://github.com/sindresorhus/type-fest
License: CC0-1.0, MIT licenses found
1665917700
Hidden Bar lets you hide menu bar items to give your Mac a cleaner look.
The Hidden Bar is notarized before distributed out side App Store. It's safe to use π
brew install --cask hiddenbar
β
+ drag to move the Hidden icons around in the menu bar.This project exists thanks to all the people who contribute. Thank you guys so much π
Please read this before you make a contribution.
macOS version >= 10.13
Author: Dwarvesf
Source Code: https://github.com/dwarvesf/hidden
License: MIT license
1663613460
In today's post we will learn about 10 Favorite Go Libraries for General utilities and tools to make your life easier.
Table of contents:
Process manager for Golang applications with an HTTP API.
A(guia) P(rocess) M(anager)
APM - Aguia Process Manager APM is a lightweight process manager written in Golang for Golang applications. It helps you keep your applications alive forever, reload and start them from the source code.
Starting an application is easy:
$ ./apm bin app-name --source="github.com/topfreegames/apm"
This will basically compile your project source code and start it as a daemon in the background. The application will have already be downloaded into GOPATH
issuing something like
go get github.com/topfreegames/apm
You will probably be able to run anything in any directory, as long as it is under GOPATH
$ go get github.com/topfreegames/apm
In order to properly use APM, you always need to start a server. This will be changed in the next version, but in the meantime you need to run the command bellow to start using APM.
$ apm serve
If no config file is provided, it will default to a folder '.apmenv' where apm
is first started.
$ apm serve-stop
A scanner similar to bufio.Scanner, but it reads and returns lines in reverse order, starting at a given position and going backward.
Ever needed or wondered how to efficiently search for something in a log file, but starting at the end and going backward? Here's your solution.
Package backscanner
provides a scanner similar to bufio.Scanner
, but it reads and returns lines in reverse order, starting at a given position (which may be the end of the input) and going backward.
This library only uses the standard library, but the test uses an external package. To install this library (along with the test dependency), simply run:
go get -t github.com/icza/backscanner
Advancing and accessing lines of the input is done by calling Scanner.Line()
, which returns the next line (previous in the source) as a string
.
For maximum efficiency there is Scanner.LineBytes()
. It returns the next line as a byte slice, which shares its backing array with the internal buffer of Scanner
. This is because no copy is made from the line data; but this also means you can only inspect or search in the slice before calling Line()
or LineBytes()
again, as the content of the internal bufferβand thus slices returned by LineBytes()
βmay be overwritten. If you need to retain the line data, make a copy of it or use Line()
.
Example using it:
input := "Line1\nLine2\nLine3"
scanner := backscanner.New(strings.NewReader(input), len(input))
for {
line, pos, err := scanner.Line()
if err != nil {
fmt.Println("Error:", err)
break
}
fmt.Printf("Line position: %2d, line: %q\n", pos, line)
}
Output:
Line position: 12, line: "Line3"
Line position: 6, line: "Line2"
Line position: 0, line: "Line1"
Error: EOF
Using it to efficiently scan a file, finding last occurrence of a string ("error"
):
f, err := os.Open("mylog.txt")
if err != nil {
panic(err)
}
fi, err := f.Stat()
if err != nil {
panic(err)
}
defer f.Close()
scanner := backscanner.New(f, int(fi.Size()))
what := []byte("error")
for {
line, pos, err := scanner.LineBytes()
if err != nil {
if err == io.EOF {
fmt.Printf("%q is not found in file.\n", what)
} else {
fmt.Println("Error:", err)
}
break
}
if bytes.Contains(line, what) {
fmt.Printf("Found %q at line position: %d, line: %q\n", what, pos, line)
break
}
}
The Go tool that will drive you to the AOP world!
In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a "pointcut" specification
Getting Started
go get -u github.com/wesovilabs/beyond
Add beyond to go.mod.
go.mod
module github.com/myrepository/myapp
...
require github.com/wesovilabs/beyond v0.0.1
...
Documentation
Beyond Documentation is published at http://wesovilabs.github.io/beyond
Verify or remove blanks and whitespace from strings.
The Blank package offers two main functionalities.
Blank can remove whitespace from a string. The package defines whitepsace as a character that is not typically visible. These characters range anywhere from the ordinary space to a less common vertical tab.
Blank can check if a string is blank. The package considers a string to be blank if it is comprised solely of whitespace.
If you do not have Go installed yet, you can find installation instructions here.
To pull the most recent version of Blank, use go get
.
go get -u github.com/Henry-Sarabia/blank
Then import the package into your project.
import "github.com/Henry-Sarabia/blank"
The package considers whitespace to be any character that is not typically visible. The most common of these characters are: space, tab, newline, return, formfeed, nonbreaking space, and vertical tab. For more information, visit the unicode package and the unicode seperator category.
To remove the whitespace from a string, use the Remove
function.
phrase := "this is a phrase"
str := blank.Remove(phrase)
fmt.Println(str)
// output: "thisisaphrase"
The package considers a string to be blank if it is comprised solely of whitespace.
For example, assume we are creating a search function that takes a string as a search query. We want to avoid searching for blank queries. Blank queries can be detected using the Is
function.
func search(qry string) error {
if blank.Is(qry) {
// return error
}
// rest of code
}
Similarly, the Has
function can process an entire slice of strings; it will check if any of the strings are blank.
Let's slightly alter our example. Assume the search function takes a slice of strings as a list of queries. We still want to avoid seraching for blank queries. Blank queries can be detected using the Has
function.
func search(qrs []string) error {
if blank.Has(qrs) {
// return error
}
// rest of code
}
Perform any number of actions on any set of OS signals in Go.
Bleep
is used to peform actions on OS signals. It is highly extensible and goroutine safe. It is possible to add any number of actions and all of them are guaranteed to be performed simultaneously on the OS signals that Bleep
will be listening for.
go get github.com/sinhashubham95/bleep
The Bleep
package allows you to create a new instance of the handler and also has a default handler in place that can be used directly.
Creating separate Bleep instances can be useful, when you want to perform different set of actions for different set of OS signals.
This is used to create a new handler for performing actions on OS Signals.
import (
"os"
"github.com/sinhashubham95/bleep"
)
func New() {
handler := bleep.New()
// now this handler can be used to add or remove actions and listen to the OS signals
}
This is used to add an action to be executed on the OS signal listening for.
import (
"os"
"github.com/sinhashubham95/bleep"
)
fun Add() {
key := bleep.Add(func (s os.Signal) {
// do something
})
// this key is the unique identifier for your added action
}
This is used to remove an action added to Bleep.
import (
"github.com/sinhashubham95/bleep"
)
func Remove() {
action := bleep.Remove("some-key") // this key should be the same as the one returned during adding the action
// the returned action is the one that was added using this key
}
Blazingly fast CLI tool for creating projects from boilerplate templates.
Features
Installation
Binaries for Linux & OSX are built automatically by Travis every release. You can download them directly or run the installation script.
Please see Installation page for more information.
Getting Started with Boilr
Use boilr help
to get the list of available commands.
In order to download a template from a github repository, use the following command:
boilr template download <github-repo-path> <template-tag>
boilr template download tmrts/boilr-license license
The downloaded template will be saved to local boilr
registry.
In order to save a template from filesystem to the template registry use the following command:
boilr template save <template-path> <template-tag>
boilr template save ~/boilr-license license
The saved template will be saved to local boilr
registry.
For a Boilr template with the given directory structure:
.
βββ project.json
βββ README.md
βββ template
βββ LICENSE
And the following project.json
context file:
{
"Author": "Tamer Tas",
"Year": "2015",
"License": [
"Apache Software License 2.0",
"MIT",
"GNU GPL v3.0"
]
}
When using the template with the following command:
boilr template use <template-tag> <target-dir>
boilr template use license /workspace/tmrts/example-project/
The user will be prompted as follows:
[?] Please choose an option for "License"
1 - "Apache Software License 2.0"
2 - "MIT"
3 - "GNU GPL v3.0"
Select from 1..3 [default: 1]: 2
[?] Please choose a value for "Year" [default: "2015"]:
[?] Please choose a value for "Author" [default: "Tamer Tas"]:
[β] Created /workspace/tmrts/example-project/LICENSE
[β] Successfully executed the project template license in /workspace/tmrts/example-project
For more information please take a look at Usage and Creating Templates pages in the wiki.
Automated changelog tool for preparing releases with lots of customization options.
Use the discussions page for help requests and how-to questions.
Please open GitHub issues for bugs and feature requests. File an issue before creating a pull request, unless it is something simple like a typo.
If you want to contribute through code or documentation, the Contributing guide is the place to start. If you need additional help create an issue or post on discussions.
Changelog generator using a git repository with multiple configuration possibilities.
Chyle produces a changelog from a git repository.
Create a changelog from your commit history
Usage:
chyle [command]
Available Commands:
config Configuration prompt
create Create a new changelog
help Help about any command
Flags:
--debug enable debugging
-h, --help help for chyle
Use "chyle [command] --help" for more information about a command.
Run a serie of prompt to help generate quickly and easily a configuration.
Generate changelog.
Chyle fetch a range of commits using given criterias from a git repository. From those commits you can extract relevant datas from commit message, author, and so on, and add it to original payload. You can afterwards if needed, enrich your payload with various useful datas contacting external apps (shell command, apis, ....) and finally, you can publish what you harvested (to an external api, stdout, ....). You can mix all steps together, avoid some, combine some, it's up to you.
Download from release page according to your architecture chyle binary : https://github.com/antham/chyle/releases
Look at the documentation and examples, run chyle config
to launch the configuration prompt.
An efficient and feature complete Hystrix like Go implementation of the circuit breaker pattern.
Circuit is an efficient and feature complete Hystrix like Go implementation of the circuit breaker pattern. Learn more about the problems Hystrix and other circuit breakers solve on the Hystrix Wiki. A short summary of advantages are:
Usage
This example shows how to create a hello-world circuit from the circuit manager
// Manages all our circuits
h := circuit.Manager{}
// Create a circuit with a unique name
c := h.MustCreateCircuit("hello-world")
// Call the circuit
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
return nil
}, nil)
fmt.Println("Result of execution:", errResult)
// Output: Result of execution: <nil>
This example shows how fallbacks execute to return alternate errors or provide logic when the circuit is open.
// You can create circuits without using the manager
c := circuit.NewCircuitFromConfig("hello-world-fallback", circuit.Config{})
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
return errors.New("this will fail")
}, func(ctx context.Context, err error) error {
fmt.Println("Circuit failed with error, but fallback returns nil")
return nil
})
fmt.Println("Execution result:", errResult)
// Output: Circuit failed with error, but fallback returns nil
// Execution result: <nil>
It is recommended to use circuit.Execute
and a context aware function. If, however, you want to exit your run function early and leave it hanging (possibly forever), then you can call circuit.Go
.
h := circuit.Manager{}
c := h.MustCreateCircuit("untrusting-circuit", circuit.Config{
Execution: circuit.ExecutionConfig{
// Time out the context after a few ms
Timeout: time.Millisecond * 30,
},
})
errResult := c.Go(context.Background(), func(ctx context.Context) error {
// Sleep 30 seconds, way longer than our timeout
time.Sleep(time.Second * 30)
return nil
}, nil)
fmt.Printf("err=%v", errResult)
// Output: err=context deadline exceeded
Circuit Breakers in Go.
Circuitbreaker provides an easy way to use the Circuit Breaker pattern in a Go program.
Circuit breakers are typically used when your program makes remote calls. Remote calls can often hang for a while before they time out. If your application makes a lot of these requests, many resources can be tied up waiting for these time outs to occur. A circuit breaker wraps these remote calls and will trip after a defined amount of failures or time outs occur. When a circuit breaker is tripped any future calls will avoid making the remote call and return an error to the caller. In the meantime, the circuit breaker will periodically allow some calls to be tried again and will close the circuit if those are successful.
go get github.com/rubyist/circuitbreaker
Here is a quick example of what circuitbreaker provides
// Creates a circuit breaker that will trip if the function fails 10 times
cb := circuit.NewThresholdBreaker(10)
events := cb.Subscribe()
go func() {
for {
e := <-events
// Monitor breaker events like BreakerTripped, BreakerReset, BreakerFail, BreakerReady
}
}()
cb.Call(func() error {
// This is where you'll do some remote call
// If it fails, return an error
}, 0)
Circuitbreaker can also wrap a time out around the remote call.
// Creates a circuit breaker that will trip after 10 failures
// using a time out of 5 seconds
cb := circuit.NewThresholdBreaker(10)
cb.Call(func() error {
// This is where you'll do some remote call
// If it fails, return an error
}, time.Second * 5) // This will time out after 5 seconds, which counts as a failure
// Proceed as above
Circuitbreaker can also trip based on the number of consecutive failures.
// Creates a circuit breaker that will trip if 10 consecutive failures occur
cb := circuit.NewConsecutiveBreaker(10)
// Proceed as above
Circuitbreaker can trip based on the error rate.
// Creates a circuit breaker based on the error rate
cb := circuit.NewRateBreaker(0.95, 100) // trip when error rate hits 95%, with at least 100 samples
// Proceed as above
Thank you for following this article.
Learn Go Programming by Building 11 Projects β Full Course
1662126600
Cabin is the best JavaScript and Node.js logging service and logging npm package
Supports Node v6.4+, Browsers (IE 10+), Express, Koa, and Lad
Cabin is a drop-in replacement and the best alternative to Sentry, Timber, Airbrake, Papertrail, Loggly, Bugsnag, or <service>
β€οΈ Love this project? Support @niftylettuce's FOSS on Patreon or PayPal :unicorn:
npm install cabin
const express = require('express');
const Cabin = require('cabin'); // <-- step 1
const app = express();
const cabin = new Cabin(); // <-- step 2
app.use(cabin.middleware); // <-- step 3
app.listen(3000);
See our Usage section below for a much more detailed and feature-rich example setup.
Cabin will automatically detect and mask the following list of extremely sensitive types of data in your logs:
*Credit card numbers from the following providers are automatically detected and masked: Visa, Mastercard, American Express, Diners Club, Discover, JCB, UnionPay, Maestro, Mir, Elo, Hiper, Hipercard
Reduce your disk storage costs through Cabin's automatic conversion of Streams, Buffers, and ArrayBuffers to simplified, descriptive-only objects that otherwise would be unreadable (and obviously pollute your log files and disk storage).
Before:
{
"request": {
"body": {
"file": {
"type": "Buffer",
"data": [
76,
111,
114,
101,
109,
32,
105,
112,
115,
117,
109,
32,
100,
111,
108,
111,
114,
32,
115,
105,
116,
'...'
]
}
}
}
}
After
{
"request": {
"body": {
"file": {
"type": "Buffer",
"byteLength": 2787
}
}
}
}
Cabin works with the most popular Node.js HTTP frameworks (e.g. Express and Koa), request body handling packages (e.g. multer and body-parser), and the passport authentication framework.
It supports Node v6.4+ and IE 10+ out of the box, and its browser-ready bundle is only 39 KB (minified and gzipped).
npx browserslist
and_chr 74
and_ff 66
and_qq 1.2
and_uc 11.8
android 67
baidu 7.12
bb 10
bb 7
chrome 74
chrome 73
chrome 72
edge 18
edge 17
firefox 66
firefox 65
ie 11
ie 10
ie_mob 11
ie_mob 10
ios_saf 12.2
ios_saf 12.0-12.1
kaios 2.5
op_mini all
op_mob 46
op_mob 12.1
opera 58
opera 57
safari 12.1
safari 12
samsung 9.2
samsung 8.2
Axe is the underlying logging add-on that allows you to record, store, back-up, and customize your log handling over HTTP or with your own custom logic.
You will find an entire example for logging errors (and more) to your Slack channel under its section Send Logs To Slack.
Cabin was built by an expert based off best practices; over a decade of experience in logging and application development β and most importantly from their agony with existing tools, services, packages, and platforms.
It was made to be both a simple and quick drop-in replacement for existing services. You can even bring your own logger! Want to use Axe, pino, signale, morgan, bunyan, winston, or another logger? No problem.
We built this with Bunyan-style compatibility β this means you won't have to change your logging argument style from log(meta, message)
to log(message, meta)
; we automatically detect Bunyan style (Metadata first, message second) and flip the order for you.
As of v6.1.1 we have added support for Bunyan style (meta, message, [, ...args])
usage (e.g. logger.info({ some: 'obj' }, 'message with format specifiers %s and %d', 'foobar', 100)
), prior to v6.1.1 we only supported (meta, message)
usage.
No need for rubber duck debugging β Cabin makes everything transparent at a glance.
Rich metadata is automatically added to your logs, so that you can easily record, analyze, and detect user behavior and application events, errors, and more:
Example Application:
const express = require('express');
const Cabin = require('cabin');
const multer = require('multer');
const requestReceived = require('request-received');
const responseTime = require('response-time');
const requestId = require('express-request-id');
const app = express();
const cabin = new Cabin();
const upload = multer();
app.use(requestReceived);
app.use(responseTime());
app.use(requestId());
app.use(cabin.middleware);
app.post(
'/',
upload.fields([
{
name: 'avatar',
maxCount: 1
},
{
name: 'boop',
maxCount: 2
}
]),
(req, res) => {
req.logger.info('visited home page');
res.send('hello world');
}
});
app.listen(3000);
Example Console Output (using Signale):
βΉ info visited home page { id: '5d1b9e484ebd2adcdfd29bf4',
timestamp: '2019-07-02T18:11:20.000Z',
request:
{ method: 'POST',
query: { foo: 'bar', beep: 'boop' },
headers:
{ host: '127.0.0.1:55370',
'accept-encoding': 'gzip, deflate',
'user-agent': 'node-superagent/3.8.3',
authorization: 'Basic ********************',
accept: 'application/json',
cookie: 'foo=bar;beep=boop',
'content-type':
'multipart/form-data; boundary=--------------------------028474125060986605281677',
'content-length': '1599',
connection: 'close' },
cookies: { foo: 'bar', beep: 'boop' },
url: '/?foo=bar&beep=boop',
body:
'{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"**********","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
timestamp: '2019-07-02T18:11:20.331Z',
id: '33afc3c5-1571-4249-b024-876b6f687b65',
http_version: '1.1',
files:
'{"avatar":[{"fieldName":"avatar","originalName":"avatar.png","clientReportedMimeType":"image/png","clientReportedFileExtension":".png","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/N6NE8A8","size":216,"detectedMimeType":"image/png","detectedFileExtension":".png","stream":{"type":"Stream"}}],"boop":[{"fieldName":"boop","originalName":"boop-1.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/PCB8YTR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}},{"fieldName":"boop","originalName":"boop-2.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/EKMAKXR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}}]}' },
user: { ip_address: '::ffff:127.0.0.1' },
duration: 1.741299,
app:
{ name: 'parse-request',
version: '2.0.1',
node: 'v10.15.3',
hash: '75783ef9d0a9c1c71f83ee352754a14ead0a3138',
tag: 'v2.0.1',
environment: 'test',
hostname: 'jacks-MacBook-Pro.local',
pid: 56543 } }
βΉ info ::ffff:127.0.0.1 user POST /?foo=bar&beep=boop HTTP/1.1 200 1951 - 67.819 ms { id: '5d1b9e484ebd2adcdfd29bf5',
timestamp: '2019-07-02T18:11:20.000Z',
request:
{ method: 'POST',
query: { foo: 'bar', beep: 'boop' },
headers:
{ host: '127.0.0.1:55370',
'accept-encoding': 'gzip, deflate',
'user-agent': 'node-superagent/3.8.3',
authorization: 'Basic ********************',
accept: 'application/json',
cookie: 'foo=bar;beep=boop',
'content-type':
'multipart/form-data; boundary=--------------------------028474125060986605281677',
'content-length': '1599',
connection: 'close' },
cookies: { foo: 'bar', beep: 'boop' },
url: '/?foo=bar&beep=boop',
body:
'{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"**********","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
timestamp: '2019-07-02T18:11:20.331Z',
id: '33afc3c5-1571-4249-b024-876b6f687b65',
http_version: '1.1',
files:
'{"avatar":[{"fieldName":"avatar","originalName":"avatar.png","clientReportedMimeType":"image/png","clientReportedFileExtension":".png","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/N6NE8A8","size":216,"detectedMimeType":"image/png","detectedFileExtension":".png","stream":{"type":"Stream"}}],"boop":[{"fieldName":"boop","originalName":"boop-1.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/PCB8YTR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}},{"fieldName":"boop","originalName":"boop-2.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/EKMAKXR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}}]}' },
user: { ip_address: '::ffff:127.0.0.1' },
response:
{ headers:
{ 'x-request-id': '33afc3c5-1571-4249-b024-876b6f687b65',
'content-type': 'application/json; charset=utf-8',
'content-length': '1951',
'x-response-time': '67.819ms',
date: 'Tue, 02 Jul 2019 18:11:20 GMT',
connection: 'close' },
http_version: '1.1',
status_code: 200,
reason_phrase: 'OK',
timestamp: '2019-07-02T18:11:20.000Z',
duration: 67.819 },
duration: 2.320237,
app:
{ name: 'parse-request',
version: '2.0.1',
node: 'v10.15.3',
hash: '75783ef9d0a9c1c71f83ee352754a14ead0a3138',
tag: 'v2.0.1',
environment: 'test',
hostname: 'jacks-MacBook-Pro.local',
pid: 56543 } }
npm:
npm install cabin
yarn:
yarn add cabin
Don't want to configure this yourself? You can simply use Lad which has this all built-in for you.
const Cabin = require('cabin');
const cabin = new Cabin();
cabin.info('hello world');
cabin.error(new Error('oops!'));
Each log level should be invoked with two arguments message
and meta
.
message
(String or Error) - this should be either a String or an Error objectmeta
(Object or Error) - this is optional and will automatically be set to an object that inherits properties from config.meta
and requests parsed. If this is an Error object, then this error will be automatically added and transformed to the meta
object's meta.err
property (e.g. { err: <Error>, ... }
)app.use(cabin.middleware);
See either the Node or Browser instructions below for further route middleware usage and proper setup.
The examples below show how to use Cabin in combination with Axe, Signale logging utility (for development), Pino logging utility (for production), and how to add an accurate
X-Response-Time
response time metric to your logs and response headers automatically.
Don't want to configure this yourself? We highly recommend to use Lad instead of configuring this yourself as it has all of this pre-configured for you with best-practices. However if you already have an existing Koa based project the example below will sufficiently serve as a guide for implementation.
Install required and recommended dependencies:
npm install koa cabin signale pino request-received koa-better-response-time koa-better-request-id
Implement the example code below (also found here):
const Koa = require('koa');
const Cabin = require('cabin');
const Router = require('koa-router');
const requestReceived = require('request-received');
const responseTime = require('koa-better-response-time');
const requestId = require('koa-better-request-id');
const { Signale } = require('signale');
const pino = require('pino')({
customLevels: {
log: 30
},
hooks: {
// <https://github.com/pinojs/pino/blob/master/docs/api.md#logmethod>
logMethod(inputArgs, method) {
return method.call(this, {
// <https://github.com/pinojs/pino/issues/854>
// message: inputArgs[0],
msg: inputArgs[0],
meta: inputArgs[1]
});
}
}
});
const env = process.env.NODE_ENV || 'development';
const app = new Koa();
const router = new Router();
const cabin = new Cabin({
// (optional: your free API key from https://cabinjs.com)
// key: 'YOUR-CABIN-API-KEY',
axe: {
logger: env === 'production' ? pino : new Signale()
}
});
// adds request received hrtime and date symbols to request object
// (which is used by Cabin internally to add `request.timestamp` to logs
app.use(requestReceived);
// adds `X-Response-Time` header to responses
app.use(responseTime());
// adds or re-uses `X-Request-Id` header
app.use(requestId());
// use the cabin middleware (adds request-based logging and helpers)
app.use(cabin.middleware);
// add your user/session management middleware here (e.g. passport)
// ...
// an example home page route
router.get('/', ctx => {
ctx.logger.info('visited home page');
ctx.body = 'hello world';
});
// this assumes that you are using passport which
// exposes `ctx.logout` to log out the logged in user
router.get('/logout', ctx => {
ctx.logger.warn('Logged out');
ctx.logout();
ctx.redirect('/');
});
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000, () => {
cabin.info('app started');
});
See Koa convenience methods below for helper utilities you can use while writing code.
Install required and recommended dependencies:
npm install express cabin signale pino request-received response-time express-request-id
Implement the example code below (also found here):
const express = require('express');
const Cabin = require('cabin');
const requestReceived = require('request-received');
const responseTime = require('response-time');
const requestId = require('express-request-id');
const { Signale } = require('signale');
const pino = require('pino')({
customLevels: {
log: 30
},
hooks: {
// <https://github.com/pinojs/pino/blob/master/docs/api.md#logmethod>
logMethod(inputArgs, method) {
return method.call(this, {
// <https://github.com/pinojs/pino/issues/854>
// message: inputArgs[0],
msg: inputArgs[0],
meta: inputArgs[1]
});
}
}
});
const env = process.env.NODE_ENV || 'development';
const app = express();
const cabin = new Cabin({
// (optional: your free API key from https://cabinjs.com)
// key: 'YOUR-CABIN-API-KEY',
axe: {
logger: env === 'production' ? pino : new Signale()
}
});
// adds request received hrtime and date symbols to request object
// (which is used by Cabin internally to add `request.timestamp` to logs
app.use(requestReceived);
// adds `X-Response-Time` header to responses
app.use(responseTime());
// adds or re-uses `X-Request-Id` header
app.use(requestId());
// use the cabin middleware (adds request-based logging and helpers)
app.use(cabin.middleware);
// add your user/session management middleware here (e.g. passport)
// ...
// an example home page route
app.get('/', (req, res) => {
req.logger.info('visited home page');
res.send('hello world');
});
// this assumes that you are using passport which
// exposes `req.logout` to log out the logged in user
app.get('/logout', (req, res) => {
req.logger.warn('logged out');
req.logout();
res.redirect('/');
});
app.listen(3000, () => {
cabin.info('app started');
});
See Express convenience methods below for helper utilities you can use while writing code.
In order to easily interact and use the logger
utility function exposed by app.use(cabin.middleware)
, we expose convenient helper methods in Express and Koa:
Express
req.log
req.logger
res.log
res.logger
Koa
ctx.log
ctx.logger
ctx.request.log
ctx.request.logger
ctx.response.log
ctx.response.logger
This is the solution for you if you're just using <script>
tags everywhere!
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/cabin"></script>
<script type="text/javascript">
(function() {
var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
cabin.setUser({
id: '1',
email: 'niftylettuce@gmail.com',
full_name: 'niftylettuce'
});
cabin.info('viewed docs');
})();
</script>
Required Browser Features
We recommend using https://polyfill.io (specifically with the bundle mentioned in VanillaJS above):
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
This assumes you are using browserify, webpack, rollup, or another bundler.
const Cabin = require('cabin');
const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });
cabin.setUser({
id: '1',
email: 'niftylettuce@gmail.com',
full_name: 'niftylettuce'
});
cabin.info('viewed docs');
For server-side logging of requests, the Cabin middleware cabin.middleware
will automatically log requests for you upon completion. Just make sure you are using express-request-id
middleware like in the examples above in order for the X-Request-Id
header to be set (and re-used if already exists, e.g. generated from client side as in below). If you're using Koa make sure to use koa-better-request-id
as shown in the examples above.
We strongly recommend that you implement one of the following code snippets with xhook (for either VanillaJS or Bundler approaches) so that all your XHR requests have a X-Request-Id
automatically added (which in turn ensures both client and server have matching request ID's). Imagine how awesome your logs will be when you can see the full trace starting with the client!
HTML
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/xhook"></script>
<script src="https://unpkg.com/cabin"></script>
<script src="https://unpkg.com/parse-request"></script>
<script src="https://unpkg.com/cuid"></script>
<script>
(function() {
var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
cabin.setUser({
id: '1',
email: 'niftylettuce@gmail.com',
full_name: 'niftylettuce'
});
xhook.before(function(req) {
if (typeof req.headers !== 'object') req.headers = {};
if (!req.headers['X-Request-Id'])
req.headers['X-Request-Id'] = cuid();
if (!req.headers['User-Agent'])
req.headers['User-Agent'] = window.navigator.userAgent;
if (!req.headers['Referer'])
req.headers['Referer'] = window.document.referrer;
if (!req.headers['Cookie'])
req.headers['Cookie'] = window.document.cookie;
cabin.info('xhr', parseRequest({ req: req }));
});
})();
</script>
Pug
You can do a similar approach with React, EJS, or another templating language.
script(src='https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet')
script(src='https://unpkg.com/xhook')
script(src='https://unpkg.com/cabin')
script(src='https://unpkg.com/parse-request')
script(src='https://unpkg.com/cuid')
script.
(function() {
var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
cabin.setUser({
id: '1',
email: 'niftylettuce@gmail.com',
full_name: 'niftylettuce'
});
xhook.before(function(req) {
if (typeof req.headers !== 'object') req.headers = {};
if (!req.headers['X-Request-Id'])
req.headers['X-Request-Id'] = cuid();
if (!req.headers['X-Request-Id'])
req.headers['X-Request-Id'] = cuid();
if (!req.headers['User-Agent'])
req.headers['User-Agent'] = window.navigator.userAgent;
if (!req.headers['Referer'])
req.headers['Referer'] = window.document.referrer;
if (!req.headers['Cookie'])
req.headers['Cookie'] = window.document.cookie;
cabin.info('xhr', parseRequest({ req: req }));
});
})();
Bundler
npm:
npm install cabin xhook cuid
yarn:
yarn add cabin xhook cuid
const Cabin = require('cabin');
const xhook = require('xhook');
const parseRequest = require('parse-request');
const cuid = require('cuid');
const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
cabin.setUser({
id: '1',
email: 'niftylettuce@gmail.com',
full_name: 'niftylettuce'
});
xhook.before(req => {
if (typeof req.headers !== 'object') req.headers = {};
if (!req.headers['X-Request-Id'])
req.headers['X-Request-Id'] = cuid();
//
// NOTE: you may want to add User-Agent, Referer, and Cookie (see above)
//
cabin.info('xhr', parseRequest({ req: req }));
});
We leave it up to you to decide how you wish to handle stack traces and errors, but we've documented our approaches for Node and Browser environments below.
If you're using Lad, then you don't need to worry about error handling, as it's built-in (complete with graceful reloading, even for database connections).
However you can otherwise use a tool such as uncaught to listen for errors, or bind purely to process
events emitted as shown below:
const Cabin = require('cabin');
const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });
process.on('uncaughtException', err => {
cabin.error(err);
process.exit(1);
});
process.on('unhandledRejection', err => {
cabin.error(err);
});
Since cross-browser support is very limited and unstandardized for errors and stack traces, we highly recommend to use StackTrace.
StackTrace
We recommend to use StackTrace instead of TraceKit as it is a more modern alternative and provides much similarity between your Browser and your Node errors (stackframes are basically similar to representations in Gecko and V8, aka the ones you get with Node).
It does require you to have a polyfill if you're using it in the browser (only if you're supporting browsers that don't support standardized Promises/JSON). You'll basically need es6-promise
and json3
polyfills for browsers you wish to support that don't have them. The example below shows you how to polyfill, don't worry! You can reference Caniuse data on Promises and JSON respectively if you need.
The example below demonstrates using StackTrace with uncaught to catch global errors below, but note that uncaught only supports IE11+.
If you're curious why it won't work in IE11, please see this great documentation on JavaScript errors cross-browser here - in particular the section on "No Error object provided".
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/stackframe"></script>
<script src="https://unpkg.com/stacktrace-js"></script>
<!-- Use this instead of the above if you need to polyfill for IE11 support -->
<!-- <script src="https://unpkg.com/stacktrace-js/dist/stacktrace-with-promises-and-json-polyfills.js"></script> -->
<script src="https://unpkg.com/uncaught"></script>
<script src="https://unpkg.com/cabin"></script>
<script src="https://unpkg.com/prepare-stack-trace"></script>
<script type="text/javascript">
(function() {
//
// Sourced from the StackTrace example from CabinJS docs
// <https://github.com/cabinjs/cabin#stacktrace>
//
var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });
// Use cabin globally in your app (instead of `console`)
window.cabin = cabin;
// Bind event listeners
uncaught.start();
uncaught.addListener(function(err, event) {
if (!err) {
if (typeof ErrorEvent === 'function' && event instanceof ErrorEvent)
return cabin.error(event.message, { event: event });
cabin.error({ event: event });
return;
}
// this will transform the error's `stack` property
// to be consistently similar to Gecko and V8 stackframes
StackTrace.fromError(err)
.then(function(stackframes) {
err.stack = prepareStackTrace(err, stackframes);
cabin.error(err);
})
.catch(function(err2) {
cabin.error(err);
cabin.error(err2);
});
});
})();
</script>
Under the hood, Cabin uses Axe which provides us with several options, including one to show metadata (e.g. request headers, body, and user) and another to show stack traces for errors.
You can pass these options through the axe
option (see Options below), or you could pass environment flags when you need to.
By default, Axe does not output any metadata and only outputs stack traces in non-production environments.
To show or hide metadata, pass a true or false value for the process environment variables SHOW_META
(defaults to true
), SHOW_META_APP
(defaults to false
), or specify a comma separated list of fields to selectively omit via OMIT_META_FIELDS
(e.g. OMIT_META_FIELDS=user
to omit meta.user
from output).
We have configured default metadata output in console logs to be sensible defaults as to not pollute your debugging experience. We welcome suggestions for how to improve this as well.
(e.g.
SHOW_META=0
orSHOW_META=false
before running your script, such asSHOW_META=false node app
).
Similarly if you pass a truthy value of 1
or true
it will show metadata (which is the default behavior).
To hide stack traces, pass a falsey value for the process environment variable SHOW_STACK
.
(e.g.
SHOW_STACK=0
orSHOW_STACK=false
before running your script, such asSHOW_STACK=false node app
).
Similarly if you pass a truthy value of 1
or true
it will show metadata (which is the default behavior).
key
(String) - defaults to an empty string, this is where you put your Cabin API key, which you can get for free at Cabincapture
(Boolean) - defaults to false
in browser (all environments) and server-side (non-production only) environments, whether or not to POST
logs to the endpoint (see Axe docs for more info)axe
(Object) - defaults to an empty Object {}
, but you can pass options here for Axelogger
(Object) - if you have a custom logger you wish to use instead of Axe, but note that Axe accepts a logger
option, so you should use that instead, see Axe docs for more infometa
(Object) - defaults to an empty object - this will get passed as metadata (e.g. you could set a custom meta.user
object here for every request)parseRequest
(Object) - defaults to an empty object, which means it will use the defaults from parse-request (see Metadata below)errorProps
(Array) - a list of properties to cherry-pick from the error object parsed out of err thanks to parse-err (by default all properties are returned; even non-enumerable ones and ones on the prototype object) (see Metadata below)message
(Function) - inspired by morgan, and defaults to a dev-friendly format (or if in production mode, then it uses a standard Apache common log format)). β when requests finish, it will utilize logger
to output an error, warn, or info level log based off the status code, and this function is used to determine the string sent to the logger. It accepts one argument options
, which is comprised of options.level
, options.req
, options.res
, and optionally (if and only if Koa) options.ctx
. It is required that this function return a String. See src/message.js for the default message function. Note that both dev-friendly and Apache common log formats are stripped of basic auth lines for obvious security reasons.We use the package parse-request to parse the request metadata for you autoamaticaly.
Here's an example of a parsed metadata object:
{
request: {
method: 'POST',
query: {
foo: 'bar',
beep: 'boop'
},
headers: {
host: '127.0.0.1:63955',
'accept-encoding': 'gzip, deflate',
'user-agent': 'node-superagent/3.8.3',
authorization: 'Basic ********************',
accept: 'application/json',
cookie: 'foo=bar;beep=boop',
'content-type': 'multipart/form-data; boundary=--------------------------930511303948232291410214',
'content-length': '1599',
connection: 'close'
},
cookies: {
foo: 'bar',
beep: 'boop'
},
body: '{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"1234567890","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
url: '/?foo=bar&beep=boop',
timestamp: '2019-06-14T07:46:55.568Z',
id: 'fd6225ed-8db0-4862-8566-0c0ad6f4c7c9',
http_version: '1.1',
files: '{"avatar":[{"fieldname":"avatar","originalname":"avatar.png","encoding":"7bit","mimetype":"image/png","buffer":{"type":"Buffer","byteLength":216},"size":216}],"boop":[{"fieldname":"boop","originalname":"boop-1.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7},{"fieldname":"boop","originalname":"boop-2.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7}]}'
},
user: {
ip_address: '::ffff:127.0.0.1'
},
id: '5d0350ef2ca74d11ee6e4f01',
timestamp: '2019-06-14T07:46:55.000Z',
duration: 6.651317
}
ctx.throw
awesome!Name | Website |
---|---|
Nick Baugh | http://niftylettuce.com/ |
Axe, Lad, Lass, Cabin, Lipo, and their respective logos are trademarks of Niftylettuce LLC. These trademarks may not be reproduced, distributed, transmitted, or otherwise used, except with the prior written permission of Niftylettuce LLC. If you are seeking permission to use these trademarks, then please contact us.
Author: Cabinjs
Source Code: https://github.com/cabinjs/cabin
License: MIT license
1660856760
Utilities for formatting strings and character vectors to for capitalization, word break and white space. Supported formats are: snake_case, spine-case, camelCase, PascalCase, Title Case, UPPERCASE, lowercase, Sentence case or combinations thereof. 'lettercase' strives to provide a simple, consistent, intuitive and high performing interface.
Latest Release:
install.packages('lettercase')
Development Version:
install.packages('devtools')
devtools::install_github('decisionpatterns/lettercase')
Author: Decisionpatterns
Source Code: https://github.com/decisionpatterns/lettercase
License: View license
1659664140
You don't (may not) need Lodash/Underscore
Lodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.
You are welcome to contribute with more items provided below.
If you are targeting legacy JavaScript engine with those ES5 methods, you can use es5-shim
Please note that, the examples used below are just showing you the native alternative of performing certain tasks. For some functions, Lodash provides you more options than native built-ins. This list is not a 1:1 comparison.
Please send a PR if you want to add or modify the code. No need to open an issue unless it's something big and you want to discuss.
Make use of native JavaScript object and array utilities before going big.
βCody Lindley, Author of jQuery Cookbook and JavaScript Enlightenment
You probably don't need Lodash. Nice List of JavaScript methods which you can use natively.
βDaniel Lamb, Computer Scientist, Technical Reviewer of Secrets of the JavaScript Ninja and Functional Programming in JavaScript
βTero Parviainen, Author of build-your-own-angular
I'll admit, I've been guilty of overusing #lodash. Excellent resource.
β@therebelrobot, Maker of web things, Facilitator for Node.js/io.js
If you're using ESLint, you can install a plugin that will help you identify places in your codebase where you don't (may not) need Lodash/Underscore.
Install the plugin...
npm install --save-dev eslint-plugin-you-dont-need-lodash-underscore
...then update your config
"extends" : ["plugin:you-dont-need-lodash-underscore/compatible"],
For more information, see Configuring the ESLint Plugin
βImportant: Note that, while many Lodash methods are null safe (e.g. _.keys, _.entries), this is not necessarily the case for their Native equivalent. If null safety is critical for your application, we suggest that you take extra precautions [e.g. consider using the native Object.keys as Object.keys(value || {})].
βImportant: Note that most native equivalents are array methods, and will not work with objects. If this functionality is needed and no object method is provided, then Lodash/Underscore might be the better option. Bear in mind however, that all iterable objects can easily be converted to an array by use of the spread operator.
Creates an array of elements split into groups the length of size.
// Underscore/Lodash
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
// Native
const chunk = (input, size) => {
return input.reduce((arr, item, idx) => {
return idx % size === 0
? [...arr, [item]]
: [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
}, []);
};
chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | 12.0 β | 16.0 β | β | 37.0 β | 8.0 β |
Creates an array with all falsy values removed.
// Underscore/Lodash
_.compact([0, 1, false, 2, '', 3]);
// Native
[0, 1, false, 2, '', 3].filter(Boolean)
array.prototype.filter
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Creates a new array concatenating array with any additional arrays and/or values.
// Underscore/Lodash
var array = [1]
var other = _.concat(array, 2, [3], [[4]])
console.log(other)
// output: [1, 2, 3, [4]]
// Native
var array = [1]
var other = array.concat(2, [3], [[4]])
console.log(other)
// output: [1, 2, 3, [4]]
Array.prototype.concat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | 5.5 β | β | β |
Similar to without, but returns the values from array that are not present in the other arrays.
// Underscore/Lodash
console.log(_.difference([1, 2, 3, 4, 5], [5, 2, 10]))
// output: [1, 3, 4]
// Native
var arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];
console.log(arrays.reduce(function(a, b) {
return a.filter(function(value) {
return !b.includes(value);
});
}));
// output: [1, 3, 4]
// ES6
let arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];
console.log(arrays.reduce((a, b) => a.filter(c => !b.includes(c))));
// output: [1, 3, 4]
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Creates a slice of array with n elements dropped from the beginning.
// Underscore/Lodash
_.drop([1, 2, 3]);
// => [2, 3]
_.drop([1, 2, 3], 2);
// => [3]
// Native
[1, 2, 3].slice(1);
// => [2, 3]
[1, 2, 3].slice(2);
// => [3]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
Creates a slice of array with n elements dropped at the end.
// Underscore/Lodash
_.dropRight([1, 2, 3]);
// => [1, 2]
_.dropRight([1, 2, 3], 2);
// => [1]
// Native
[1, 2, 3].slice(0, -1);
// => [1, 2]
[1, 2, 3].slice(0, -2);
// => [1]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
Fills elements of array with value from start up to, but not including, end. Note that fill
is a mutable method in both native and Lodash/Underscore.
// Underscore/Lodash
var array = [1, 2, 3]
_.fill(array, 'a')
console.log(array)
// output: ['a', 'a', 'a']
_.fill(Array(3), 2)
// output: [2, 2, 2]
_.fill([4, 6, 8, 10], '*', 1, 3)
// output: [4, '*', '*', 10]
// Native
var array = [1, 2, 3]
array.fill('a')
console.log(array)
// output: ['a', 'a', 'a']
Array(3).fill(2)
// output: [2, 2, 2]
[4, 6, 8, 10].fill('*', 1, 3)
// output: [4, '*', '*', 10]
Array.prototype.fill()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 31.0 β | β | 32.0 β | 8 β |
Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
// Underscore/Lodash
var users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'fred', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
]
_.find(users, function (o) { return o.age < 40; })
// output: object for 'barney'
// Native
var users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'fred', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
]
users.find(function (o) { return o.age < 40; })
// output: object for 'barney'
Array.prototype.find()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 25.0 β | β | 32.0 β | 7.1 β |
Returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.
// Underscore/Lodash
var users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'fred', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
]
var index = _.findIndex(users, function (o) { return o.age >= 40; })
console.log(index)
// output: 1
// Native
var users = [
{ 'user': 'barney', 'age': 36, 'active': true },
{ 'user': 'fred', 'age': 40, 'active': false },
{ 'user': 'pebbles', 'age': 1, 'active': true }
]
var index = users.findIndex(function (o) { return o.age >= 40; })
console.log(index)
// output: 1
Array.prototype.findIndex()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 25.0 β | β | 32.0 β | 7.1 β |
Returns the first element of an array. Passing n will return the first n elements of the array.
// Underscore/Lodash
_.first([1, 2, 3, 4, 5]);
// => 1
// Underscore
_.first([1, 2, 3, 4, 5], 2);
// => [1, 2]
// Native
[1, 2, 3, 4, 5][0];
// => 1
//or
[].concat(1, 2, 3, 4, 5).shift()
// => 1
//or
[].concat([1, 2, 3, 4, 5]).shift()
// => 1
// Native (works even with potentially undefined/null, like _.first)
[].concat(undefined).shift()
// => undefined
[1, 2, 3, 4, 5].slice(0, 2);
// => [1, 2]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
Flattens array a single level deep.
// Underscore/Lodash
_.flatten([1, [2, [3, [4]], 5]]);
// => [1, 2, [3, [4]], 5]
// Native
const flatten = [1, [2, [3, [4]], 5]].reduce( (a, b) => a.concat(b), [])
// => [1, 2, [3, [4]], 5]
const flatten = [].concat(...[1, [2, [3, [4]], 5]])
// => [1, 2, [3, [4]], 5]
// Native(ES2019)
const flatten = [1, [2, [3, [4]], 5]].flat()
// => [1, 2, [3, [4]], 5]
const flatten = [1, [2, [3, [4]], 5]].flatMap(number => number)
// => [1, 2, [3, [4]], 5]
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | β | 3.0 β | 9.0 β | 10.5 β | 4 β |
Array.prototype.flat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
69 β | β | 62 β | β | 56 β | 12 β |
Array.prototype.flatMap()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
69 β | β | 62 β | β | 56 β | 12 β |
Recursively flattens array.
// Underscore/Lodash
_.flattenDeep([1, [2, [3, [4]], 5]]);
// => [1, 2, 3, 4, 5]
// Native
const flattenDeep = (arr) => Array.isArray(arr)
? arr.reduce( (a, b) => a.concat(flattenDeep(b)) , [])
: [arr]
flattenDeep([1, [[2], [3, [4]], 5]])
// => [1, 2, 3, 4, 5]
// Native(ES2019)
[1, [2, [3, [4]], 5]].flat(Infinity)
// => [1, 2, 3, 4, 5]
const flattenDeep = (arr) => arr.flatMap((subArray, index) => Array.isArray(subArray) ? flattenDeep(subArray) : subArray)
flattenDeep([1, [[2], [3, [4]], 5]])
// => [1, 2, 3, 4, 5]
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | β | 16.0 β | β | 37.0 β | 7.1 β |
Array.prototype.flat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
69 β | β | 62 β | β | 56 β | 12 β |
Array.prototype.flatMap()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
69 β | β | 62 β | β | 56 β | 12 β |
Returns an object composed from key-value pairs.
// Underscore/Lodash
_.fromPairs([['a', 1], ['b', 2]]);
// => { 'a': 1, 'b': 2 }
// Native
const fromPairs = function(arr) {
return arr.reduce(function(accumulator, value) {
accumulator[value[0]] = value[1];
return accumulator;
}, {})
}
// Compact form
const fromPairs = (arr) => arr.reduce((acc, val) => (acc[val[0]] = val[1], acc), {})
fromPairs([['a', 1], ['b', 2]]);
// => { 'a': 1, 'b': 2 }
// Native(ES2019)
Object.fromEntries([['a', 1], ['b', 2]])
// => { 'a': 1, 'b': 2 }
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Object.fromEntries()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
73.0 β | 79.0 β | 63.0 β | β | 60 β | 12.1 β |
Gets the first element or all but the first element.
const array = [1, 2, 3]
// Underscore: _.first, _.head, _.take
// Lodash: _.first, _.head
_.head(array)
// output: 1
// Underscore: _.rest, _.tail, _.drop
// Lodash: _.tail
_.tail(array)
// output: [2, 3]
// Native
const [ head, ...tail ] = array
console.log(head)
// output: 1
console.log(tail)
// output [2, 3]
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | 12.0 β | 16.0 β | β | 37.0 β | 8.0 β |
Returns the first index at which a given element can be found in the array, or -1 if it is not present.
// Underscore/Lodash
var array = [2, 9, 9]
var result = _.indexOf(array, 2)
console.log(result)
// output: 0
// Native
var array = [2, 9, 9]
var result = array.indexOf(2)
console.log(result)
// output: 0
Array.prototype.indexOf()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Returns an array that is the intersection of all the arrays. Each value in the result is present in each of the arrays.
// Underscore/Lodash
console.log(_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]))
// output: [1, 2]
// Native
var arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];
console.log(arrays.reduce(function(a, b) {
return a.filter(function(value) {
return b.includes(value);
});
}));
// output: [1, 2]
// ES6
let arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];
console.log(arrays.reduce((a, b) => a.filter(c => b.includes(c))));
// output: [1, 2]
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Creates a slice of array with n elements taken from the end. :heavy_exclamation_mark: Native slice does not behave entirely the same as the Lodash
method. See example below to understand why.
// Underscore/Lodash
_.takeRight([1, 2, 3]);
// => [3]
_.takeRight([1, 2, 3], 2);
// => [2, 3]
_.takeRight([1, 2, 3], 5);
// => [1, 2, 3]
// Native
[1, 2, 3].slice(-1);
// => [3]
[1, 2, 3].slice(-2);
// => [2, 3]
[1, 2, 3].slice(-5);
// => [1, 2, 3]
// Difference in compatibility
// Lodash
_.takeRight([1, 2, 3], 0);
// => []
// Native
[1, 2, 3].slice(0);
// => [1, 2, 3]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
Returns true if given value is an array.
// Lodash
var array = []
console.log(_.isArray(array))
// output: true
// Native
var array = []
console.log(Array.isArray(array));
// output: true
Array.isArray()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 4.0 β | 9.0 β | 10.5 β | 5.0 β |
Checks if value is classified as an ArrayBuffer object.
// Lodash
_.isArrayBuffer(new ArrayBuffer(2));
// output: true
// Native
console.log(new ArrayBuffer(2) instanceof ArrayBuffer);
// output: true
:warning: You will get the wrong result if you get ArrayBuffer
from another realm. See details.
instanceof
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Joins a list of elements in an array with a given separator.
// Lodash
var result = _.join(['one', 'two', 'three'], '--')
console.log(result)
// output: 'one--two--three'
// Native
var result = ['one', 'two', 'three'].join('--')
console.log(result)
// output: 'one--two--three'
Array.prototype.join()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | 5.5 β | β | β |
Returns the last element of an array. Passing n will return the last n elements of the array.
// Underscore/Lodash
const numbers = [1, 2, 3, 4, 5];
_.last(numbers);
// => 5
// Underscore
_.last(numbers, 2);
// => [4, 5]
// Native
const numbers = [1, 2, 3, 4, 5];
numbers[numbers.length - 1];
// => 5
//or
numbers.slice(-1)[0];
// => 5
//or
[].concat(numbers).pop()
// => 5
// Native (works even with potentially undefined/null)
[].concat(undefined).pop()
// => undefined
numbers.slice(-2);
// => [4, 5]
Array.prototype.concat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | 5.5 β | β | β |
Returns the index of the last occurrence of value in the array, or -1 if value is not present.
// Underscore/Lodash
var array = [2, 9, 9, 4, 3, 6]
var result = _.lastIndexOf(array, 9)
console.log(result)
// output: 2
// Native
var array = [2, 9, 9, 4, 3, 6]
var result = array.lastIndexOf(9)
console.log(result)
// output: 2
Array.prototype.lastIndexOf()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.
// Lodash
var array = [1, 2, 3]
console.log(_.reverse(array))
// output: [3, 2, 1]
// Native
var array = [1, 2, 3]
console.log(array.reverse())
// output: [3, 2, 1]
Voice from the Lodash author:
Lodash's
_.reverse
just callsArray#reverse
and enables composition like_.map(arrays, _.reverse).
It's exposed on _ because previously, likeUnderscore
, it was only exposed in the chaining syntax. --- jdalton
Array.prototype.reverse()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9 β | β | β |
Returns a shallow copy of a portion of an array into a new array object selected from begin
to end
(end
not included)
// Lodash
var array = [1, 2, 3, 4]
console.log(_.slice(array, 1, 3))
// output: [2, 3]
// Native
var array = [1, 2, 3, 4]
console.log(array.slice(1, 3));
// output: [2, 3]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Returns an array where matching items are filtered.
// Lodash
var array = [1, 2, 3]
console.log(_.without(array, 2))
// output: [1, 3]
// Native
var array = [1, 2, 3]
console.log(array.filter(function(value) {
return value !== 2;
}));
// output: [1, 3]
Array.prototype.filter()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.5 β | 9 β | β | β |
Returns everything but the last entry of the array. Pass n to exclude the last n elements from the result.
// Underscore
var array = [5, 4, 3, 2, 1]
console.log(_.initial(array, 2))
// output: [5, 4, 3]
// Native
var array = [5, 4, 3, 2, 1]
console.log(array.slice(0, -2));
// output: [5, 4, 3]
Array.prototype.slice()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | β | β | β |
Removes all provided values from the given array using strict equality for comparisons, i.e. ===.
// Lodash
const array = [1, 2, 3, 1, 2, 3];
_.pull(array, 2, 3);
console.log(array); // output: [1, 1]
// Native JS
const array = [1, 2, 3, 1, 2, 3];
function pull(arr, ...removeList){
var removeSet = new Set(removeList)
return arr.filter(function(el){
return !removeSet.has(el)
})
}
console.log(pull(array, 2, 3)); // output: [1, 1]
console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!
// TypeScript
const array = [1, 2, 3, 1, 2, 3];
const pull = <T extends unknown>(sourceArray: T[], ...removeList: T[]): T[] => {
const removeSet = new Set(removeList);
return sourceArray.filter(el => !removeSet.has(el));
};
console.log(pull(array, 2, 3)); // output: [1, 1]
console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!
Array.prototype.filter()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.5 β | 9 β | β | β |
Set.prototype.has()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
38 β | 12 β | 13 β | 11 β | 25 β | 8 β |
Creates an array of unique values, taking an iteratee
to compute uniqueness with (note that to iterate by a key in an object you must use x => x.key
instead of key
for the iteratee
)
// Lodash
var array1 = [2.1];
var array2 = [1.2, 2.3];
var result = _.unionBy(array1, array2, Math.floor)
console.log(result)
// output: [2.1, 1.2]
// Native
var array1 = [2.1];
var array2 = [1.2, 2.3];
function unionBy(...arrays) {
const iteratee = (arrays).pop();
if (Array.isArray(iteratee)) {
return []; // return empty if iteratee is missing
}
return [...arrays].flat().filter(
(set => (o) => set.has(iteratee(o)) ? false : set.add(iteratee(o)))(new Set()),
);
};
console.log(unionBy(array1, array2, Math.floor))
// output: [2.1, 1.2]
Array.prototype.flat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
69 β | β | 62 β | β | 56 β | 12 β |
Array.isArray()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 4.0 β | 9.0 β | 10.5 β | 5.0 β |
Set.prototype.has()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
38 β | 12 β | 13 β | 11 β | 25 β | 8 β |
:heavy_exclamation_mark:Important: Note that most native equivalents are array methods, and will not work with objects. If this functionality is needed and no object method is provided, then Lodash/Underscore is the better option.
Iterates over a list of elements, yielding each in turn to an iteratee function.
// Underscore/Lodash
//For arrays
_.each([1, 2, 3], function (value, index) {
console.log(value)
})
// output: 1 2 3
//For objects
_.each({'one':1, 'two':2, 'three':3}, function(value) {
console.log(value)
})
// output: 1 2 3
// Native
//For arrays
[1, 2, 3].forEach(function (value, index) {
console.log(value)
})
// output: 1 2 3
//For objects
Object.entries({'one':1, 'two':2, 'three':3}).forEach(function([key,value],index) {
console.log(value)
})
//output: 1 2 3
Array.prototype.forEach()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Object.entries().forEach()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
54 β | 14 β | 47 β | β | 41 β | 10.1β |
Tests whether all elements in the array pass the test implemented by the provided function.
// Underscore/Lodash
function isLargerThanTen (element, index, array) {
return element >= 10
}
var array = [10, 20, 30]
var result = _.every(array, isLargerThanTen)
console.log(result)
// output: true
// Native
function isLargerThanTen (element, index, array) {
return element >= 10
}
var array = [10, 20, 30]
var result = array.every(isLargerThanTen)
console.log(result)
// output: true
Array.prototype.every()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Creates a new array with all elements that pass the test implemented by the provided function.
// Underscore/Lodash
function isBigEnough (value) {
return value >= 10
}
var array = [12, 5, 8, 130, 44]
var filtered = _.filter(array, isBigEnough)
console.log(filtered)
// output: [12, 130, 44]
// Native
function isBigEnough (value) {
return value >= 10
}
var array = [12, 5, 8, 130, 44]
var filtered = array.filter(isBigEnough)
console.log(filtered)
// output: [12, 130, 44]
Array.prototype.filter()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9 β | β | β |
Group items by key.
// Underscore/Lodash
var grouped = _.groupBy(['one', 'two', 'three'], 'length')
console.log(grouped)
// output: {3: ["one", "two"], 5: ["three"]}
// Native
var grouped = ['one', 'two', 'three'].reduce((r, v, i, a, k = v.length) => ((r[k] || (r[k] = [])).push(v), r), {})
console.log(grouped)
// output: {3: ["one", "two"], 5: ["three"]}
// Underscore/Lodash
var grouped = _.groupBy([1.3, 2.1, 2.4], num => Math.floor(num))
console.log(grouped)
// output: {1: [1.3], 2: [2.1, 2.4]}
// Native
var grouped = [1.3, 2.1, 2.4].reduce((r, v, i, a, k = Math.floor(v)) => ((r[k] || (r[k] = [])).push(v), r), {})
console.log(grouped)
// output: {1: [1.3], 2: [2.1, 2.4]}
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Checks if a value is in collection.
var array = [1, 2, 3]
// Underscore/Lodash - also called _.contains
_.includes(array, 1)
// output: true
// Native
var array = [1, 2, 3]
array.includes(1)
// output: true
// Native (does not use same value zero)
var array = [1, 2, 3]
array.indexOf(1) > -1
// output: true
Array.prototype.includes
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
47.0 β | 14.0 β | 43.0 β | β | 34.0 β | 9.0 β |
Array.prototype.indexOf
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
:heavy_exclamation_mark: Not in Underscore.js
Creates an object composed of keys generated from the results of running each element of collection through iteratee.
// Lodash
console.log(_.keyBy(['a', 'b', 'c']))
// output: { a: 'a', b: 'b', c: 'c' }
console.log(_.keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))
// output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }
console.log(_.keyBy({ data: { id: 'a1', title: 'abc' }}, 'id'))
// output: { a1: { id: 'a1', title: 'abc' }}
// keyBy for array only
const keyBy = (array, key) => (array || []).reduce((r, x) => ({ ...r, [key ? x[key] : x]: x }), {});
// Native
console.log(keyBy(['a', 'b', 'c']))
// output: { a: 'a', b: 'b', c: 'c' }
console.log(keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))
// output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }
console.log(keyBy(Object.values({ data: { id: 'a1', title: 'abc' }}), 'id'))
// output: { a1: { id: 'a1', title: 'abc' }}
// keyBy for array and object
const collectionKeyBy = (collection, key) => {
const c = collection || {};
return c.isArray() ? keyBy(c, key) : Object.values(keyBy(c, key));
}
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | 12.0 β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Translates all items in an array or object to new array of items.
// Underscore/Lodash
var array1 = [1, 2, 3]
var array2 = _.map(array1, function (value, index) {
return value * 2
})
console.log(array2)
// output: [2, 4, 6]
// Native
var array1 = [1, 2, 3]
var array2 = array1.map(function (value, index) {
return value * 2
})
console.log(array2)
// output: [2, 4, 6]
// Underscore/Lodash
var object1 = { 'a': 1, 'b': 2, 'c': 3 }
var object2 = _.map(object1, function (value, index) {
return value * 2
})
console.log(object2)
// output: [2, 4, 6]
// Native
var object1 = { 'a': 1, 'b': 2, 'c': 3 }
var object2 = Object.entries(object1).map(function ([key, value], index) {
return value * 2
})
console.log(object2)
// output: [2, 4, 6]
Object.entries()
and destructuring![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | β | β | β |
Array.prototype.map()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Use Array#reduce for find the maximum or minimum collection item
// Underscore/Lodash
var data = [{ value: 6 }, { value: 2 }, { value: 4 }]
var minItem = _.minBy(data, 'value')
var maxItem = _.maxBy(data, 'value')
console.log(minItem, maxItem)
// output: { value: 2 } { value: 6 }
// Native
var data = [{ value: 6 }, { value: 2 }, { value: 4 }]
var minItem = data.reduce(function(a, b) { return a.value <= b.value ? a : b }, {})
var maxItem = data.reduce(function(a, b) { return a.value >= b.value ? a : b }, {})
console.log(minItem, maxItem)
// output: { value: 2 }, { value: 6 }
Extract a functor and use es2015 for better code
// utils
const makeSelect = (comparator) => (a, b) => comparator(a, b) ? a : b
const minByValue = makeSelect((a, b) => a.value <= b.value)
const maxByValue = makeSelect((a, b) => a.value >= b.value)
// main logic
const data = [{ value: 6 }, { value: 2 }, { value: 4 }]
const minItem = data.reduce(minByValue, {})
const maxItem = data.reduce(maxByValue, {})
console.log(minItem, maxItem)
// output: { value: 2 }, { value: 6 }
// or also more universal and little slower variant of minBy
const minBy = (collection, key) => {
// slower because need to create a lambda function for each call...
const select = (a, b) => a[key] <= b[key] ? a : b
return collection.reduce(select, {})
}
console.log(minBy(data, 'value'))
// output: { value: 2 }
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
array.map
or _.map
can also be used to replace _.pluck
. Lodash v4.0 removed _.pluck
in favor of _.map
with iteratee shorthand. Details can be found in Changelog
// Underscore/Lodash
var array1 = [{name: "Alice"}, {name: "Bob"}, {name: "Jeremy"}]
var names = _.pluck(array1, "name")
console.log(names)
// output: ["Alice", "Bob", "Jeremy"]
// Native
var array1 = [{name: "Alice"}, {name: "Bob"}, {name: "Jeremy"}]
var names = array1.map(function(x){
return x.name
})
console.log(names)
// output: ["Alice", "Bob", "Jeremy"]
Array.prototype.map()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
// Underscore/Lodash
var array = [0, 1, 2, 3, 4]
var result = _.reduce(array, function (previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue
})
console.log(result)
// output: 10
// Native
var array = [0, 1, 2, 3, 4]
var result = array.reduce(function (previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue
})
console.log(result)
// output: 10
Array.prototype.reduce()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Creates an array of numbers progressing from start up to.
// Underscore/Lodash
_.range(4) // output: [0, 1, 2, 3]
_.range(-4) // output: [0, -1, -2, -3]
_.range(1, 5) // output: [1, 2, 3, 4]
_.range(0, 20, 5) // output: [0, 5, 10, 15]
// Native ( solution with Array.from )
Array.from({length: 4}, (_, i) => i) // output: [0, 1, 2, 3]
Array.from({length: 4}, (_, i) => -i) // output: [-0, -1, -2, -3]
Array.from({length: 4}, (_, i) => i + 1) // output: [1, 2, 3, 4]
Array.from({length: 4}, (_, i) => i * 5) // output: [0, 5, 10, 15]
// Native ( solution with keys() and spread )
[...Array(4).keys()] // output: [0, 1, 2, 3]
[...Array(4).keys()].map(k => -k) // output: [-0, -1, -2, -3]
[...Array(4).keys()].map(k => k + 1) // output: [1, 2, 3, 4]
[...Array(4).keys()].map(k => k * 5) // output: [0, 5, 10, 15]
Array.from()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 32.0 β | β | β | 9.0 β |
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | 12.0 β | 16.0 β | β | 37.0 β | 7.1 β |
This method is like _.reduce except that it iterates over elements of collection from right to left.
// Underscore/Lodash
var array = [0, 1, 2, 3, 4]
var result = _.reduceRight(array, function (previousValue, currentValue, currentIndex, array) {
return previousValue - currentValue
})
console.log(result)
// output: -2
// Native
var array = [0, 1, 2, 3, 4]
var result = array.reduceRight(function (previousValue, currentValue, currentIndex, array) {
return previousValue - currentValue
})
console.log(result)
// output: -2
Array.prototype.reduceRight()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
The opposite of _.filter; this method returns the elements of collection that predicate does not return truthy for.
// Underscore/Lodash
var array = [1, 2, 3, 4, 5];
var result = _.reject(array, function (x) {
return x % 2 === 0;
});
// output: [1, 3, 5]
// Native
var array = [1, 2, 3, 4, 5];
var reject = function (arr, predicate) {
var complement = function (f) {
return function (x) {
return !f(x);
}
};
return arr.filter(complement(predicate));
};
// output: [1, 3, 5]
Array.prototype.filter()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | 12 β | 1.5 β | 9.0 β | 9.5 β | 3.0 β |
Gets a random element from array
.
// Underscore/Lodash
const array = [0, 1, 2, 3, 4]
const result = _.sample(array)
console.log(result)
// output: 2
// Native
const array = [0, 1, 2, 3, 4]
const sample = arr => {
const len = arr == null ? 0 : arr.length
return len ? arr[Math.floor(Math.random() * len)] : undefined
}
const result = sample(array)
console.log(result)
// output: 2
Array.prototype.length()
and Math.random()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
Returns the number of values in the collection.
// Underscore/Lodash
var result = _.size({one: 1, two: 2, three: 3})
console.log(result)
// output: 3
// Native
var result2 = Object.keys({one: 1, two: 2, three: 3}).length
console.log(result2)
// output: 3
Object.keys()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 4.0 β | 9.0 β | 12.0 β | 5.0 β |
Tests whether any of the elements in the array pass the test implemented by the provided function.
// Underscore/Lodash
function isLargerThanTen (element, index, array) {
return element >= 10
}
var array = [10, 9, 8]
var result = _.some(array, isLargerThanTen)
console.log(result)
// output: true
// Native
function isLargerThanTen (element, index, array) {
return element >= 10
}
var array = [10, 9, 8]
var result = array.some(isLargerThanTen)
console.log(result)
// output: true
Array.prototype.some()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | β 9.0 | β | β |
Sorts an array of object based on an object key provided by a parameter (note this is more limited than Underscore/Lodash).
const fruits = [
{name:"banana", amount: 2},
{name:"apple", amount: 4},
{name:"pineapple", amount: 2},
{name:"mango", amount: 1}
];
// Underscore
_.sortBy(fruits, 'name');
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]
// Lodash
_.orderBy(fruits, ['name'],['asc']);
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]
// Native
const sortBy = (key) => {
return (a, b) => (a[key] > b[key]) ? 1 : ((b[key] > a[key]) ? -1 : 0);
};
// The native sort modifies the array in place. `_.orderBy` and `_.sortBy` do not, so we use `.concat()` to
// copy the array, then sort.
fruits.concat().sort(sortBy("name"));
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]
Array.prototype.concat()
and Array.prototype.sort()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
1.0 β | β | 1.0 β | 5.5 β | β | β |
Produces a duplicate-free version of the array, using === to test object equality.
// Underscore/Lodash
var array = [1, 2, 1, 4, 1, 3]
var result = _.uniq(array)
console.log(result)
// output: [1, 2, 4, 3]
// Native
var array = [1, 2, 1, 4, 1, 3];
var result = [...new Set(array)];
console.log(result)
// output: [1, 2, 4, 3]
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | 12.0 β | 16.0 β | β | 37.0 β | 8.0 β |
:heavy_exclamation_mark:Note this is an alternative implementation
Creates a version of the function that will only be run after first being called count times. Useful for grouping asynchronous responses, where you want to be sure that all the async calls have finished, before proceeding.
var notes = ['profile', 'settings']
// Underscore/Lodash
var renderNotes = _.after(notes.length, render)
notes.forEach(function (note) {
console.log(note)
renderNotes()
})
// Native
notes.forEach(function (note, index) {
console.log(note)
if (notes.length === (index + 1)) {
render()
}
})
Array.prototype.forEach()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.5 β | 9.0 β | β | β |
Create a new function that calls func with thisArg and args.
var objA = {
x: 66,
offsetX: function(offset) {
return this.x + offset;
}
}
var objB = {
x: 67
};
// Underscore/Lodash
var boundOffsetX = _.bind(objA.offsetX, objB, 0);
// Native
var boundOffsetX = objA.offsetX.bind(objB, 0);
Function.prototype.bind()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
7.0 β | β | 4.0 β | 9.0 β | 11.6 β | 5.1 β |
Checks if value is classified as a Function object.
// Lodash
_.isFunction(console.log);
// => true
_.isFunction(/abc/);
// => false
// Native
function isFunction(func) {
return typeof func === "function";
}
isFunction(setTimeout);
// => true
isFunction(123);
// => false
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Create a new function that calls func with thisArg and args.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
}
// Avoid costly calculations while the window size is in flux.
jQuery(window).on('resize', debounce(calculateLayout, 150));
debounce
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
7.0 β | β | 4.0 β | 9.0 β | 11.6 β | 5.1 β |
Create a new function that calls func with args.
// Lodash
function greet(greeting, name) {
return greeting + ' ' + name;
}
var sayHelloTo = _.partial(greet, 'Hello');
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'
// Native
function greet(greeting, name) {
return greeting + ' ' + name;
}
var sayHelloTo = (...args) => greet('Hello', ...args)
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'
// Native
const partial = (func, ...boundArgs) => (...remainingArgs) => func(...boundArgs, ...remainingArgs)
var sayHelloTo = partial(greet, 'Hello');
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
46.0 β | 12.0 β | 16.0 β | β | 37.0 β | 8.0 β |
Create a new function that limits calls to func to once every given timeframe.
function throttle(func, timeFrame) {
var lastTime = 0;
return function (...args) {
var now = new Date();
if (now - lastTime >= timeFrame) {
func(...args);
lastTime = now;
}
};
}
// Avoid running the same function twice within the specified timeframe.
jQuery(window).on('resize', throttle(calculateLayout, 150));
throttle
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | 12.0 β | 3.0 β | 9.0 β | 10.5 β | 4.0 β |
Puts the value into an array of length one if it is not already an array.
// Underscore
console.log(_.castArray(5))
// output: [5]
console.log(_.castArray([2]))
// output: [2]
// Native
function castArray(arr) {
return Array.isArray(arr) ? arr : [arr]
}
// output: true
console.log(castArray(5));
// output: [5]
console.log(castArray([2]));
// output: [2]
Array.isArray()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 4.0 β | 9.0 β | 10.5 β | 5.0 β |
Checks if value is classified as a Date object.
// Lodash
console.log(_.isDate(new Date));
// output: true
// Native
console.log(Object.prototype.toString.call(new Date) === "[object Date]");
// output: true
String.prototype.toString.call()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if value is greater than other.
// Lodash
console.log(_.gt(3, 1))
// output: true
// Native
console.log(3 > 1);
// output: true
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if value is greater than or equal to other.
// Lodash
console.log(_.gte(3, 1))
// output: true
// Native
console.log(3 >= 1);
// output: true
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if value is an empty object or collection.
:heavy_exclamation_mark:Note that the Native version does not support evaluating a Set or a Map
// Lodash
console.log(_.isEmpty(null))
// output: true
console.log(_.isEmpty(''))
// output: true
console.log(_.isEmpty({}))
// output: true
console.log(_.isEmpty([]))
// output: true
console.log(_.isEmpty({a: '1'}))
// output: false
// Native
const isEmpty = obj => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;
console.log(isEmpty(null))
// output: true
console.log(isEmpty(''))
// output: true
console.log(isEmpty({}))
// output: true
console.log(isEmpty([]))
// output: true
console.log(isEmpty({a: '1'}))
// output: false
Array.prototype.includes()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
47.0 β | 14.0 β | 43.0 β | β | 34.0 β | 9.0 β |
Checks if value is a finite primitive number.
// Lodash
console.log(_.isFinite('3'))
// output: false
console.log(_.isFinite(3))
// output: true
// Native
console.log(Number.isFinite('3'))
// output: false
console.log(Number.isFinite(3))
// output: true
Number.isFinite()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
19.0 β | β | 16.0 β | β | 15.0 β | 9.0 β |
Checks if value is an integer.
// Lodash
console.log(_.isInteger(3))
// output: true
console.log(_.isInteger('3'))
// output: false
// Native
console.log(Number.isInteger(3))
// output: true
console.log(Number.isInteger('3'))
// output: false
Number.isInteger()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | 12 β | 16.0 β | β | β | β |
Checks if a value is NaN.
// Underscore/Lodash
console.log(_.isNaN(NaN))
// output: true
// Native
console.log(isNaN(NaN))
// output: true
// ES6
console.log(Number.isNaN(NaN))
// output: true
MDN:
In comparison to the global
isNaN()
function,Number.isNaN()
doesn't suffer the problem of forcefully converting the parameter to a number. This means it is now safe to pass values that would normally convert toNaN
, but aren't actually the same value asNaN
. This also means that only values of the type number, that are alsoNaN
, return true. Number.isNaN()
Voice from the Lodash author:
Lodash's
_.isNaN
is equiv to ES6Number.isNaN
which is different than the globalisNaN
. --- jdalton
isNaN
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
Number.isNaN
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
25.0 β | β | 15.0 β | β | β | 9.0 β |
:heavy_exclamation_mark:Not in Underscore.js
Checks if value is null or undefined.
// Lodash
console.log(_.isNil(null))
// output: true
console.log(_.isNil(NaN))
// output: false
console.log(_.isNil(undefined))
// output: true
// Native
console.log(null == null);
// output: true
console.log(NaN == null);
// output: false
console.log(undefined == null)
// output: true
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if value is null or undefined.
// Underscore/Lodash
console.log(_.isNull(null))
// output: true
console.log(_.isNull(void 0))
// output: false
// Native
console.log(null === null);
// output: true
console.log(void 0 === null);
// output: false
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if value is undefined.
// Underscore/Lodash
console.log(_.isUndefined(a))
// output: true
// Native
console.log(typeof a === 'undefined');
// output: true
console.log(a === undefined);
// output: true
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1 β | β | β | β |
The method is used to copy the values of all enumerable own properties from one or more source objects to a target object.
// Underscore: _.extendOwn
// Lodash
function Foo() {
this.c = 3;
}
function Bar() {
this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = _.assign(new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'e': 5 }
// Native
function Foo() {
this.c = 3;
}
function Bar() {
this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = Object.assign({}, new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'e': 5 }
Object.assign()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 34.0 β | β | 32.0 β | 9.0 β |
The method is used to apply new values over an object with default values for keys.
// Underscore: _.defaults
// Lodash
const newValues = {a: 3};
const defaultValues = {a: 1, b: 2}
const appliedValues = _.defaults(newValues, defaultValues);
console.log(appliedValues)
// output { a: 3, b: 2 }
// Native
const newValues = {a: 3};
const defaultValues = {a: 1, b: 2}
const appliedValues = Object.assign({}, defaultValues, newValues);
// output { a: 3, b: 2 }
Object.assign()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 34.0 β | β | 32.0 β | 9.0 β |
The method is used to copy the values of all enumerable own and inherited properties from one or more source objects to a target object.
// Underscore
// Lodash: _.assignIn
function Foo() {
this.c = 3;
}
function Bar() {
this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = _.extend({}, new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }
// Native
function Foo() {
this.c = 3;
}
function Bar() {
this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = Object.assign({}, new Foo, Foo.prototype, new Bar, Bar.prototype);
console.log(result);
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }
//Or using a function
const extend = (target, ...sources) => {
const length = sources.length;
if (length < 1 || target == null) return target;
for (let i = 0; i < length; i++) {
const source = sources[i];
for (const key in source) {
target[key] = source[key];
}
}
return target;
};
console.log(extend({}, new Foo, new Bar));
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }
Object.assign()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 34.0 β | β | 32.0 β | 9.0 β |
Checks if key
is a direct property of object
. Key may be a path of a value separated by .
// Lodash
var object = { a: 1, b: 'settings', c: { d: 'test' } };
var hasA = _.has(object, 'a');
var hasCWhichHasD = _.has(object, 'c.d')
console.log(hasA);
// output: true
console.log(hasCWhichHasD);
// output: true
// Native
const has = function (obj, key) {
var keyParts = key.split('.');
return !!obj && (
keyParts.length > 1
? has(obj[key.split('.')[0]], keyParts.slice(1).join('.'))
: hasOwnProperty.call(obj, key)
);
};
var object = { a: 1, b: 'settings' };
var result = has(object, 'a');
// output: true
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | 12 β | β | 5.5 β | 5 β | 3 β |
Gets the value at path of object. Note: If provided path does not exist inside the object js will generate error.
// Lodash
var object = { a: [{ b: { c: 3 } }] };
var result = _.get(object, 'a[0].b.c', 1);
console.log(result);
// output: 3
// Native (ES6 - IE not supported)
var object = { a: [{ b: { c: 3 } }] };
var { a: [{ b: { c: result = 1 } = {} } = {}] = [] } = object;
console.log(result);
// output: 3
// Native (ES11)
var object = { a: [{ b: { c: 3 } }] };
var result = object?.a?.[0]?.b?.c ?? 1;
console.log(result);
// output: 3
// Native
const get = (obj, path, defaultValue = undefined) => {
const travel = regexp =>
String.prototype.split
.call(path, regexp)
.filter(Boolean)
.reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
return result === undefined || result === obj ? defaultValue : result;
};
var object = { a: [{ b: { c: 3 } }] };
var result = get(object, 'a[0].b.c', 1);
// output: 3
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
49.0 β | 14.0 β | 41.0 β | β | 41.0 β | 8.0 β |
?.
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
80.0 β | 80.0 β | 74.0 β | β | 67.0 β | 13.1 β |
??
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
80.0 β | 80.0 β | 72.0 β | β | β | 13.1 β |
Retrieves all the names of the object's own enumerable properties.
// Underscore/Lodash
var result = _.keys({one: 1, two: 2, three: 3})
console.log(result)
// output: ["one", "two", "three"]
// Native
var result2 = Object.keys({one: 1, two: 2, three: 3})
console.log(result2)
// output: ["one", "two", "three"]
Object.keys()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 4.0 β | 9.0 β | 12.0 β | 5.0 β |
Returns a copy of the object, filtered to omit the keys specified.
var object = { 'a': 1, 'b': '2', 'c': 3 };
// Underscore/Lodash
var result = _.omit(object, ['a', 'c']);
console.log(result)
// output: { 'b': '2' }
// Native
var { a, c, ...result2 } = object;
console.log(result2)
// output: { 'b': '2' }
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
60.0 β | β | 55.0 β | β | 37.0 β | β |
Creates an object composed of the object properties predicate returns truthy for.
var object = { 'a': 1, 'b': '2', 'c': 3 };
// Underscore/Lodash
var result = _.pick(object, ['a', 'c']);
console.log(result)
// output: {a: 1, c: 3}
// Native
const { a, c } = object;
const result = { a, c};
console.log(result);
// output: {a: 1, c: 3}
// for an array of this object --> array.map(({a, c}) => ({a, c}));
// Native
function pick(object, keys) {
return keys.reduce((obj, key) => {
if (object && object.hasOwnProperty(key)) {
obj[key] = object[key];
}
return obj;
}, {});
}
var result = pick(object, ['a', 'c']);
console.log(result)
// output: {a: 1, c: 3}
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
38.0 β | β | 13.0 β | 12.0 β | 25.0 β | 7.1 β |
Creates an object composed of the object properties predicate returns truthy for.
var object = { 'a': 1, 'b': null, 'c': 3, 'd': false, 'e': undefined };
// Underscore/Lodash
var result = _.pickBy(object);
console.log(result)
// output: {a: 1, c: 3}
// Native
function pickBy(object) {
const obj = {};
for (const key in object) {
if (object[key]) {
obj[key] = object[key];
}
}
return obj;
}
var result = pickBy(object);
console.log(result)
// output: {a: 1, c: 3}
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | 6.0 β | β | β |
Retrieves all the given object's own enumerable property [ key, value ]
pairs.
// Underscore - also called _.pairs
// Lodash - also called _.entries
var result = _.toPairs({one: 1, two: 2, three: 3})
console.log(result)
// output: [["one", 1], ["two", 2], ["three", 3]]
// Native
var result2 = Object.entries({one: 1, two: 2, three: 3})
console.log(result2)
// output: [["one", 1], ["two", 2], ["three", 3]]
Object.entries()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
54.0 β | 14.0 β | 47.0 β | β | 41.0 β | 10.1 β |
Retrieves all the given object's own enumerable property values.
// Underscore/Lodash
var result = _.values({one: 1, two: 2, three: 3})
console.log(result)
// output: [1, 2, 3]
// Native
var result2 = Object.values({one: 1, two: 2, three: 3})
console.log(result2)
// output: [1, 2, 3]
Object.values()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
54.0 β | 14.0 β | 47.0 β | β | 41.0 β | 10.1 β |
:heavy_exclamation_mark:Not in Underscore.js
Converts the first character of string to upper case and the remaining to lower case.
// Lodash
var result = _.capitalize('FRED');
console.log(result);
// => 'Fred'
// Native
const capitalize = (string) => {
return string ? string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() : '';
};
var result = capitalize('FRED');
console.log(result);
// => 'Fred'
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Checks if string ends with the given target string.
// Lodash
_.endsWith('abc', 'c');
// => true
_.endsWith('abc', 'b');
// => false
_.endsWith('abc', 'b', 2);
// => true
// Native
'abc'.endsWith('c');
// => true
'abc'.endsWith('b');
// => false
'abc'.endsWith('b', 2);
// => true
String.prototype.endsWith()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
41.0 β | β | 17.0 β | β | 28.0 β | 9.0 β |
Checks if value is classified as a String primitive or object.
// Lodash
_.isString('abc');
// => true
_.isString(123);
// => false
// Native
function isString(str){
if (str != null && typeof str.valueOf() === "string") {
return true
}
return false
}
isString('abc');
// => true
isString(123);
// => false
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Converts the first character of string to lower case.
// Lodash
var result = _.lowerFirst('Fred')
console.log(result)
// output: 'fred'
// Native
const lowerFirst = (string) => {
return string ? string.charAt(0).toLowerCase() + string.slice(1) : ''
}
var result = lowerFirst('Fred')
console.log(result)
// output: 'fred'
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Pads the current string with another string (multiple times, if needed) until the resulting string reaches the given length.
// Lodash
console.log(_.padStart('123', 5, '0'))
// output: '00123'
console.log(_.padEnd('123', 5, '0'))
// output: '12300'
// Native
console.log('123'.padStart(5, '0'))
// output: '00123'
console.log('123'.padEnd(5, '0'))
// output: '12300'
String.prototype.padStart()
and String.prototype.padEnd()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
57.0 β | 15.0 β | 48.0 β | β | 44.0 β | 10.0 β |
:heavy_exclamation_mark:Not in Underscore.js
Repeats the given string n times.
// Lodash
var result = _.repeat('abc', 2)
console.log(result)
// output: 'abcabc'
// Native
var result = 'abc'.repeat(2)
console.log(result)
// output: 'abcabc'
String.prototype.repeat()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
41.0 β | β | 24.0 β | β | 28.0 β | 9.0 β |
returns a new string with some or all matches of a pattern
replaced by a replacement
// Lodash
var re = /apples/gi;
var str = 'Apples are round, and apples are juicy.';
var newstr = _.replace(str, re, 'oranges');
console.log(newstr);
// output: 'oranges are round, and oranges are juicy.'
// Native
var re = /apples/gi;
var str = 'Apples are round, and apples are juicy.';
var result = str.replace(re, 'oranges');
console.log(result);
// output: 'oranges are round, and oranges are juicy.'
String.prototype.replace()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Splits string by separator.
// Lodash
var result = _.split('a-b-c', '-', 2)
console.log(result)
// output: ['a','b']
// Native
var result = 'a-b-c'.split('-', 2)
console.log(result)
// output: ['a','b']
String.prototype.split()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Checks if string starts with the given target string.
// Lodash
var result = _.startsWith('abc', 'b', 1)
console.log(result)
// output: true
// Native
var result = 'abc'.startsWith('b', 1)
console.log(result)
// output: true
String.prototype.startsWith()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
41.0 β | β | 17.0 β | β | 28.0 β | 9.0 β |
:heavy_exclamation_mark: Note this is an alternative implementation. Native template literals not escape html.
Create a template function.
// Lodash/Underscore
const compiled = _.template('hello <%= user %>!');
var result = compiled({ 'user': 'fred' });
console.log(result);
// output: 'hello fred'
// Native
const templateLiteral = (value) => `hello ${value.user}`;
var result = templateLiteral({ 'user': 'fred' });
console.log(result);
// output: 'hello fred'
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
41.0 β | 12.0 β | 34.0 β | β | 28.0 β | 9.0 β |
:heavy_exclamation_mark:Not in Underscore.js
Lowercases a given string.
// Lodash
var result = _.toLower('FOOBAR')
console.log(result)
// output: 'foobar'
// Native
var result = 'FOOBAR'.toLowerCase()
console.log(result)
// output: 'foobar'
String.prototype.toLowerCase()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Uppercases a given string.
// Lodash
var result = _.toUpper('foobar')
console.log(result)
// output: 'FOOBAR'
// Native
var result = 'foobar'.toUpperCase()
console.log(result)
// output: 'FOOBAR'
String.prototype.toUpperCase()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | 1.0 β | β | β | β |
:heavy_exclamation_mark:Not in Underscore.js
Removes the leading and trailing whitespace characters from a string.
// Lodash
var result = _.trim(' abc ')
console.log(result)
// output: 'abc'
// Native
var result = ' abc '.trim()
console.log(result)
// output: 'abc'
String.prototype.trim()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
5.0 β | β | 3.5 β | 9.0 β | 10.5 β | 5.0 β |
:heavy_exclamation_mark:Not in Underscore.js
Uppercases the first letter of a given string
// Lodash
var result = _.upperFirst('george')
console.log(result)
// output: 'George'
// Native
const upperFirst = (string) => {
return string ? string.charAt(0).toUpperCase() + string.slice(1) : ''
}
var result = upperFirst('george')
console.log(result)
// output: 'George'
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
similar to _.uniq except that it accepts comparator which is invoked to compare elements of array. The order of result values is determined by the order they occur in the array.
// Lodash
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
const result = _.uniqWith(objects, _.isEqual);
console.log(result);
// output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]
// Native
const uniqWith = (arr, fn) => arr.filter((element, index) => arr.findIndex((step) => fn(element, step)) === index);
const array = [1, 2, 2, 3, 4, 5, 2];
const result = uniqWith(array, (a, b) => a === b);
console.log(result);
// output: [1, 2, 3, 4, 5]
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
const result = uniqWith(objects, (a, b) => JSON.stringify(a) === JSON.stringify(b));
console.log(result);
// output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]
Array.prototype.filter()
and Array.prototype.findIndex()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | 12.0 β | 25.0 β | β | 32.0 β | 8.0 β |
Invokes the iteratee n times, returning an array of the results of each invocation.
// Lodash
var result = _.times(10)
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
// Native
var result = Array.from({length: 10}, (_,x) => x)
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
// Native
var result = [...Array(10).keys()]
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
Array.from()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
45.0 β | β | 32.0 β | β | β | 9.0 β |
Clamps number within the inclusive lower and upper bounds.
// Lodash
_.clamp(-10, -5, 5);
// => -5
_.clamp(10, -5, 5);
// => 5
_.clamp(10, -5);
// => -5
_.clamp(10, 99);
// => 10
// Native
const clamp = (number, boundOne, boundTwo) => {
if (!boundTwo) {
return Math.max(number, boundOne) === boundOne ? number : boundOne;
} else if (Math.min(number, boundOne) === number) {
return boundOne;
} else if (Math.max(number, boundTwo) === number) {
return boundTwo;
}
return number;
};
clamp(-10, -5, 5);
// => -5
clamp(10, -5, 5);
// => 5
clamp(10, -5);
// => -5
clamp(10, 99);
// => 10
Math.min() and Math.max()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Checks if n is between start and up to, but not including, end. If end is not specified, it's set to start with start then set to 0. If start is greater than end the params are swapped to support negative ranges.
// Lodash
_.inRange(3, 2, 4);
// output: true
_.inRange(-3, -2, -6);
// output: true
//Native
const inRange = (num, init, final) => {
if(final === undefined){
final = init;
init = 0;
}
return (num >= Math.min(init, final) && num < Math.max(init, final));
}
//Native
const inRange = (num, a, b=0) => (Math.min(a,b) <= num && num < Math.max(a,b));
inRange(3, 2, 4);
// output: true
inRange(-3, -2, -6);
// output: true
Math.min() and Math.max()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Produces a random number between the inclusive lower and upper bounds. If only one argument is provided a number between 0 and the given number is returned. If floating is true, or either lower or upper are floats, a floating-point number is returned instead of an integer.
// Lodash
_.random(0, 5);
// => an integer between 0 and 5
_.random(5);
// => also an integer between 0 and 5
_.random(5, true);
// => a floating-point number between 0 and 5
_.random(1.2, 5.2);
// => a floating-point number between 1.2 and 5.2
//Native ES6
const random = (a = 1, b = 0) => {
const lower = Math.min(a, b);
const upper = Math.max(a, b);
return lower + Math.random() * (upper - lower);
};
const randomInt = (a = 1, b = 0) => {
const lower = Math.ceil(Math.min(a, b));
const upper = Math.floor(Math.max(a, b));
return Math.floor(lower + Math.random() * (upper - lower + 1))
};
random();
// => a floating-point number between 0 and 1
random(5);
// => a floating-point number between 0 and 5
random(0, 5);
// => also a floating-point number between 0 and 5
random(1.2, 5.2);
// => a floating-point number between 1.2 and 5.2
randomInt();
// => just 0 or 1
randomInt(5);
// => an integer between 0 and 5
randomInt(0, 5);
// => also an integer between 0 and 5
randomInt(1.2, 5.2);
// => an integer between 2 and 5
Math.random()
![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |
---|---|---|---|---|---|
β | β | β | β | β | β |
Author: You-dont-need
Source Code: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore
License: MIT license
1648654560
Command line interface to manage clipboard
you can download a pre-compiled executable, then you should copy that executable to /usr/bin
or add it to your $PATH
env. Do not forget to chmod +x cb
.
Users of Arch Linux can install package from AUR:
curl -sSf https://sh.rustup.rs | sh
xorg-dev
and build-essential
make && sudo make install
cb -t "Text to be copied"
cb -p
cat file | cb
Usage: cb [OPTIONS]
Optional arguments:
-h, --help Prints the help message
-V, --version Prints the version
-p, --paste Pastes the content of clipboard
-c, --clear Clears the content of clipboard
-s, --server Starts server as a daemon
-r, --raw Do not print newline after pasting the content
-t, --text TEXT Store TEXT into clipboard
Download Details:
Author: yaa110
Source Code: https://github.com/yaa110/cb
License: View license
1648647180
π’ Note: This project was known as Bitwarden_RS and has been renamed to separate itself from the official Bitwarden server in the hopes of avoiding confusion and trademark/branding issues. Please see #1642 for more explanation.
Image is based on Rust implementation of Bitwarden API.
This project is not associated with the Bitwarden project nor 8bit Solutions LLC.
Basically full implementation of Bitwarden API is provided including:
Pull the docker image and mount a volume from the host for persistent storage:
docker pull vaultwarden/server:latest docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 vaultwarden/server:latest
This will preserve any persistent data under /vw-data/, you can adapt the path to whatever suits you.
IMPORTANT: Some web browsers, like Chrome, disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like Cannot read property 'importKey'
. To solve this problem, you need to access the web vault from HTTPS.
This can be configured in vaultwarden directly or using a third-party reverse proxy (some examples).
If you have an available domain name, you can get HTTPS certificates with Let's Encrypt, or you can generate self-signed certificates with utilities like mkcert. Some proxies automatically do this step, like Caddy (see examples linked above).
See the vaultwarden wiki for more information on how to configure and run the vaultwarden server.
To ask a question, offer suggestions or new features or to get help configuring or installing the software, please use the forum.
If you spot any bugs or crashes with vaultwarden itself, please create an issue. Make sure there aren't any similar issues open, though!
If you prefer to chat, we're usually hanging around at #vaultwarden:matrix.org room on Matrix. Feel free to join us!
Thanks for your contribution to the project!
Download Details:
Author: dani-garcia
Source Code: https://github.com/dani-garcia/vaultwarden#readme
License: GPL-3.0 License
1648639740
A simple Git/Mercurial/PlasticSCM tui client based on keyboard shortcuts
This project uses Cargo and pure Rust stable and works on latest versions of Windows, Mac, Linux and BSD.
Its only dependencies are:
You can either install it via cargo
or download the binaries from github releases.
If you go the cargo
route, you need to have it installed (usually using rustup). In a terminal, run this command to install verco
:
cargo install verco
Then you'll be able to run verco
from whichever directory you in.
sudo dnf copr enable atim/verco -y
sudo dnf install verco
verco
can be installed from the available AUR packages using an AUR helper. For example:
paru -S verco
In a terminal in a repository folder, type in the verco
command. It will launch verco
's tui and you'll be able to interface with Git/Mercurial/PlasticSCM.
Download Details:
Author: vamolessa
Source Code: https://github.com/vamolessa/verco
License: GPL-3.0 License
1648632360
NOTE: if you've been using freepass before June 03, 2017: you need to checkout the serde-migration
git tag, build the CLI, and mergein
your vault into a new one using that particular version.
The free password manager for power users.
core
library does everything correctly, and that the user interface passes your data to the core
library, not to an evil server.cli
versionFreepass is (going to be) available on different platforms:
cli
: for UNIX-like systemsEach version has its own README!
By participating in this project you agree to follow the Contributor Code of Conduct.
The list of contributors is available on GitHub.
Download Details:
Author: unrelentingtech
Source Code: https://github.com/unrelentingtech/freepass
License: Unlicense License