Skip to content

Commit

Permalink
Add TypeScript definition (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
BendingBender authored and sindresorhus committed Apr 6, 2019
1 parent 42cc3bf commit 5dbf51c
Show file tree
Hide file tree
Showing 5 changed files with 334 additions and 213 deletions.
168 changes: 84 additions & 84 deletions bench.js
@@ -1,95 +1,95 @@
'use strict';
const Benchmark = require('benchmark');
const m = require('.');
const dotProp = require('.');

const suite = new Benchmark.Suite();

suite
.add('get', () => {
const f1 = {foo: {bar: 1}};
m.get(f1);
f1[''] = 'foo';
m.get(f1, '');
m.get(f1, 'foo');
m.get({foo: 1}, 'foo');
m.get({foo: null}, 'foo');
m.get({foo: undefined}, 'foo');
m.get({foo: {bar: true}}, 'foo.bar');
m.get({foo: {bar: {baz: true}}}, 'foo.bar.baz');
m.get({foo: {bar: {baz: null}}}, 'foo.bar.baz');
m.get({foo: {bar: 'a'}}, 'foo.fake');
m.get({foo: {bar: 'a'}}, 'foo.fake.fake2');
m.get({'\\': true}, '\\');
m.get({'\\foo': true}, '\\foo');
m.get({'bar\\': true}, 'bar\\');
m.get({'foo\\bar': true}, 'foo\\bar');
m.get({'\\.foo': true}, '\\\\.foo');
m.get({'bar\\.': true}, 'bar\\\\.');
m.get({'foo\\.bar': true}, 'foo\\\\.bar');

const f2 = {};
Object.defineProperty(f2, 'foo', {
const fixture1 = {foo: {bar: 1}};
dotProp.get(fixture1);
fixture1[''] = 'foo';
dotProp.get(fixture1, '');
dotProp.get(fixture1, 'foo');
dotProp.get({foo: 1}, 'foo');
dotProp.get({foo: null}, 'foo');
dotProp.get({foo: undefined}, 'foo');
dotProp.get({foo: {bar: true}}, 'foo.bar');
dotProp.get({foo: {bar: {baz: true}}}, 'foo.bar.baz');
dotProp.get({foo: {bar: {baz: null}}}, 'foo.bar.baz');
dotProp.get({foo: {bar: 'a'}}, 'foo.fake');
dotProp.get({foo: {bar: 'a'}}, 'foo.fake.fake2');
dotProp.get({'\\': true}, '\\');
dotProp.get({'\\foo': true}, '\\foo');
dotProp.get({'bar\\': true}, 'bar\\');
dotProp.get({'foo\\bar': true}, 'foo\\bar');
dotProp.get({'\\.foo': true}, '\\\\.foo');
dotProp.get({'bar\\.': true}, 'bar\\\\.');
dotProp.get({'foo\\.bar': true}, 'foo\\\\.bar');

const fixture2 = {};
Object.defineProperty(fixture2, 'foo', {
value: 'bar',
enumerable: false
});
m.get(f2, 'foo');
m.get({}, 'hasOwnProperty');
dotProp.get(fixture2, 'foo');
dotProp.get({}, 'hasOwnProperty');

function fn() {}
fn.foo = {bar: 1};
m.get(fn);
m.get(fn, 'foo');
m.get(fn, 'foo.bar');
dotProp.get(fn);
dotProp.get(fn, 'foo');
dotProp.get(fn, 'foo.bar');

const f3 = {foo: null};
m.get(f3, 'foo.bar');
const fixture3 = {foo: null};
dotProp.get(fixture3, 'foo.bar');

m.get({'foo.baz': {bar: true}}, 'foo\\.baz.bar');
m.get({'fo.ob.az': {bar: true}}, 'fo\\.ob\\.az.bar');
dotProp.get({'foo.baz': {bar: true}}, 'foo\\.baz.bar');
dotProp.get({'fo.ob.az': {bar: true}}, 'fo\\.ob\\.az.bar');

m.get(null, 'foo.bar', false);
m.get('foo', 'foo.bar', false);
m.get([], 'foo.bar', false);
m.get(undefined, 'foo.bar', false);
dotProp.get(null, 'foo.bar', false);
dotProp.get('foo', 'foo.bar', false);
dotProp.get([], 'foo.bar', false);
dotProp.get(undefined, 'foo.bar', false);
})
.add('set', () => {
const func = () => 'test';
let f1 = {};
let fixture1 = {};

m.set(f1, 'foo', 2);
dotProp.set(fixture1, 'foo', 2);

f1 = {foo: {bar: 1}};
m.set(f1, 'foo.bar', 2);
fixture1 = {foo: {bar: 1}};
dotProp.set(fixture1, 'foo.bar', 2);

m.set(f1, 'foo.bar.baz', 3);
dotProp.set(fixture1, 'foo.bar.baz', 3);

m.set(f1, 'foo.bar', 'test');
dotProp.set(fixture1, 'foo.bar', 'test');

m.set(f1, 'foo.bar', null);
dotProp.set(fixture1, 'foo.bar', null);

m.set(f1, 'foo.bar', false);
dotProp.set(fixture1, 'foo.bar', false);

m.set(f1, 'foo.bar', undefined);
dotProp.set(fixture1, 'foo.bar', undefined);

m.set(f1, 'foo.fake.fake2', 'fake');
dotProp.set(fixture1, 'foo.fake.fake2', 'fake');

m.set(f1, 'foo.function', func);
dotProp.set(fixture1, 'foo.function', func);

function fn() {}
m.set(fn, 'foo.bar', 1);
dotProp.set(fn, 'foo.bar', 1);

f1.fn = fn;
m.set(f1, 'fn.bar.baz', 2);
fixture1.fn = fn;
dotProp.set(fixture1, 'fn.bar.baz', 2);

const f2 = {foo: null};
m.set(f2, 'foo.bar', 2);
const fixture2 = {foo: null};
dotProp.set(fixture2, 'foo.bar', 2);

const f3 = {};
m.set(f3, '', 3);
const fixture3 = {};
dotProp.set(fixture3, '', 3);

m.set(f1, 'foo\\.bar.baz', true);
dotProp.set(fixture1, 'foo\\.bar.baz', true);

m.set(f1, 'fo\\.ob\\.ar.baz', true);
dotProp.set(fixture1, 'fo\\.ob\\.ar.baz', true);
})
.add('delete', () => {
const func = () => 'test';
Expand All @@ -102,7 +102,7 @@ suite
func
};

const f1 = {
const fixture1 = {
foo: {
bar: {
baz: inner
Expand All @@ -113,49 +113,49 @@ suite
}
};

m.delete(f1, 'foo.bar.baz.c');
dotProp.delete(fixture1, 'foo.bar.baz.c');

m.delete(f1, 'top');
dotProp.delete(fixture1, 'top');

m.delete(f1, 'foo.bar.baz.func.foo');
dotProp.delete(fixture1, 'foo.bar.baz.func.foo');

m.delete(f1, 'foo.bar.baz.func');
dotProp.delete(fixture1, 'foo.bar.baz.func');

m.set(f1, 'foo\\.bar.baz', true);
m.delete(f1, 'foo\\.bar.baz');
dotProp.set(fixture1, 'foo\\.bar.baz', true);
dotProp.delete(fixture1, 'foo\\.bar.baz');

const f2 = {};
m.set(f2, 'foo.bar\\.baz', true);
m.delete(f2, 'foo.bar\\.baz');
const fixture2 = {};
dotProp.set(fixture2, 'foo.bar\\.baz', true);
dotProp.delete(fixture2, 'foo.bar\\.baz');

f2.dotted = {
fixture2.dotted = {
sub: {
'dotted.prop': 'foo',
other: 'prop'
}
};
m.delete(f2, 'dotted.sub.dotted\\.prop');
dotProp.delete(fixture2, 'dotted.sub.dotted\\.prop');
})
.add('has', () => {
const f1 = {foo: {bar: 1}};
m.has(f1);
m.has(f1, 'foo');
m.has({foo: 1}, 'foo');
m.has({foo: null}, 'foo');
m.has({foo: undefined}, 'foo');
m.has({foo: {bar: true}}, 'foo.bar');
m.has({foo: {bar: {baz: true}}}, 'foo.bar.baz');
m.has({foo: {bar: {baz: null}}}, 'foo.bar.baz');
m.has({foo: {bar: 'a'}}, 'foo.fake.fake2');
const fixture1 = {foo: {bar: 1}};
dotProp.has(fixture1);
dotProp.has(fixture1, 'foo');
dotProp.has({foo: 1}, 'foo');
dotProp.has({foo: null}, 'foo');
dotProp.has({foo: undefined}, 'foo');
dotProp.has({foo: {bar: true}}, 'foo.bar');
dotProp.has({foo: {bar: {baz: true}}}, 'foo.bar.baz');
dotProp.has({foo: {bar: {baz: null}}}, 'foo.bar.baz');
dotProp.has({foo: {bar: 'a'}}, 'foo.fake.fake2');

function fn() {}
fn.foo = {bar: 1};
m.has(fn);
m.has(fn, 'foo');
m.has(fn, 'foo.bar');
dotProp.has(fn);
dotProp.has(fn, 'foo');
dotProp.has(fn, 'foo.bar');

m.has({'foo.baz': {bar: true}}, 'foo\\.baz.bar');
m.has({'fo.ob.az': {bar: true}}, 'fo\\.ob\\.az.bar');
dotProp.has({'foo.baz': {bar: true}}, 'foo\\.baz.bar');
dotProp.has({'fo.ob.az': {bar: true}}, 'fo\\.ob\\.az.bar');
})
.on('cycle', event => {
console.log(String(event.target));
Expand Down
102 changes: 102 additions & 0 deletions index.d.ts
@@ -0,0 +1,102 @@
declare const dotProp: {
/**
@param obj - Object to get the `path` value.
@param path - Path of the property in the object, using `.` to separate each nested key.
Use `\\.` if you have a `.` in the key.
@param defaultValue - Default value.
@example
```
import dotProp = require('dot-prop');
dotProp.get({foo: {bar: 'unicorn'}}, 'foo.bar');
//=> 'unicorn'
dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep');
//=> undefined
dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
//=> 'default value'
dotProp.get({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
//=> 'unicorn'
```
*/
get<T = unknown>(
obj: {[key: string]: unknown},
path: string,
defaultValue?: T
): T;

/**
@param obj - Object to set the `path` value.
@param path - Path of the property in the object, using `.` to separate each nested key.
Use `\\.` if you have a `.` in the key.
@param value - Value to set at `path`.
@example
```
import dotProp = require('dot-prop');
const obj = {foo: {bar: 'a'}};
dotProp.set(obj, 'foo.bar', 'b');
console.log(obj);
//=> {foo: {bar: 'b'}}
const foo = dotProp.set({}, 'foo.bar', 'c');
console.log(foo);
//=> {foo: {bar: 'c'}}
dotProp.set(obj, 'foo.baz', 'x');
console.log(obj);
//=> {foo: {bar: 'b', baz: 'x'}}
```
*/
set<T extends {[key: string]: unknown}>(
obj: T,
path: string,
value: unknown
): T;

/**
@param obj - Object to test the `path` value.
@param path - Path of the property in the object, using `.` to separate each nested key.
Use `\\.` if you have a `.` in the key.
@example
```
import dotProp = require('dot-prop');
dotProp.has({foo: {bar: 'unicorn'}}, 'foo.bar');
//=> true
```
*/
has(obj: {[key: string]: unknown}, path: string): boolean;

/**
@param obj Object to delete the `path` value.
@param path - Path of the property in the object, using `.` to separate each nested key.
Use `\\.` if you have a `.` in the key.
@example
```
import dotProp = require('dot-prop');
const obj = {foo: {bar: 'a'}};
dotProp.delete(obj, 'foo.bar');
console.log(obj);
//=> {foo: {}}
obj.foo.bar = {x: 'y', y: 'x'};
dotProp.delete(obj, 'foo.bar.x');
console.log(obj);
//=> {foo: {bar: {y: 'x'}}}
```
*/
delete(obj: {[key: string]: unknown}, path: string): void;
};

export = dotProp;
18 changes: 18 additions & 0 deletions index.test-d.ts
@@ -0,0 +1,18 @@
import {expectType} from 'tsd';
import dotProp = require('.');

expectType<unknown>(dotProp.get({foo: {bar: 'unicorn'}}, 'foo.bar'));
expectType<unknown>(dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep'));
expectType<string>(
dotProp.get({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value')
);
expectType<unknown>(
dotProp.get({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot')
);

const obj = {foo: {bar: 'a'}};
expectType<typeof obj>(dotProp.set(obj, 'foo.bar', 'b'));

expectType<boolean>(dotProp.has({foo: {bar: 'unicorn'}}, 'foo.bar'));

expectType<void>(dotProp.delete({foo: {bar: 'a'}}, 'foo.bar'));
11 changes: 6 additions & 5 deletions package.json
Expand Up @@ -13,11 +13,12 @@
"node": ">=6"
},
"scripts": {
"test": "xo && ava",
"test": "xo && ava && tsd",
"bench": "node bench.js"
},
"files": [
"index.js"
"index.js",
"index.d.ts"
],
"keywords": [
"obj",
Expand All @@ -38,9 +39,9 @@
"is-obj": "^1.0.0"
},
"devDependencies": {
"ava": "*",
"ava": "^1.4.1",
"benchmark": "^2.1.4",
"microtime": "^2.1.8",
"xo": "*"
"tsd": "^0.7.2",
"xo": "^0.24.0"
}
}

0 comments on commit 5dbf51c

Please sign in to comment.