This repository has been archived by the owner on May 8, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
5,852 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# See https://help.github.com/ignore-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
|
||
# testing | ||
/coverage | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
npm-debug.log* | ||
yarn-debug.log* | ||
|
||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Debug log from npm | ||
npm-debug.log | ||
|
||
# sass | ||
.sass-cache/ | ||
|
||
#ngrok | ||
ngrok | ||
/.idea | ||
/reports | ||
/screenshots | ||
/dist | ||
.project | ||
npm-debug.log.* | ||
/selenium-debug.log | ||
/grocerycop-website-3.1-ui.iml | ||
/.vscode/ | ||
/lib/ | ||
/.env.local | ||
/styleguide/ | ||
/storybook-static/ | ||
/compiled/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"printWidth": 90, | ||
"semi": false, | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
language: node_js | ||
node_js: | ||
- 10 | ||
install: | ||
- npm install | ||
script: | ||
- yarn test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,39 @@ | ||
# ts-get | ||
Alternative to lodash.get that makes it typed and cool as if optional typing proposal is there | ||
|
||
Alternative to `lodash.get` that makes it typed and cool as if optional chaining proposal is there. | ||
|
||
## Usage and features | ||
|
||
```typescript | ||
import get from 'ts-get' | ||
|
||
type SomeType = { | ||
optionalField?: string | ||
nested?: { | ||
dangerousAccess?: string | ||
} | ||
} | undefined | null | ||
|
||
const input = {} | ||
const input2 = { | ||
optionalField: "value", | ||
} | ||
|
||
get(input, it => it.optionalField, "default") // -> "default" | ||
get(input2, it => it.optionalField, "default") // -> "value" | ||
get(input2, it => it.nested.dangerousAccess, "default") // -> "default" | ||
get(input2, it => it.unknownField, "default") // -> Type error, `unknownField` doesn't exist on type | ||
get(input2, it => it.optionalField, 5) // -> Type error, third argument is not assignable to type `string` | ||
``` | ||
|
||
## Difference with `lodash.get` behavior | ||
|
||
- If your path gets `null` at the end, it will bail out to `defaultValue` or `undefined`. | ||
If you would like to get `null` returned anyway, just pass it as a `defaultValue` | ||
- If your type field is of type `null` and only `null` or `undefined` your field will be of type `{}[]`. | ||
I have no idea how to fix it 🤷♂️ PR Welcome 😇🙏 | ||
```typescript | ||
type A = { | ||
field: null | undefined// -> {}[] inside of the callback and as return type too | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module.exports = { | ||
"transform": { | ||
"^.+\\.(ts|tsx)$": "ts-jest" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "ts-get", | ||
"version": "0.0.1", | ||
"description": "Alternative to lodash.get that makes it typed and cool as if optional chaining proposal is there", | ||
"main": "lib/index.node.js", | ||
"module": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"repository": "https://github.com/RIP21/ts-get.git", | ||
"author": "Andrii Los <puha212@gmail.com>", | ||
"license": "MIT", | ||
"private": false, | ||
"scripts": { | ||
"lint": "prettier --write ./**/*.ts", | ||
"prebuild": "rimraf lib", | ||
"build": "tsc && babel src/index.ts --out-file lib/index.node.js", | ||
"test": "jest src --coverage", | ||
"release": "np" | ||
}, | ||
"devDependencies": { | ||
"np": "^4.0.2", | ||
"@babel/cli": "^7.2.3", | ||
"@babel/core": "^7.3.4", | ||
"@babel/plugin-syntax-typescript": "^7.3.3", | ||
"@babel/preset-env": "^7.3.4", | ||
"@babel/preset-typescript": "^7.3.3", | ||
"@babel/runtime": "^7.3.4", | ||
"@types/jest": "^24.0.11", | ||
"@types/lodash": "^4.14.123", | ||
"jest": "^24.5.0", | ||
"lodash": "^4.17.11", | ||
"prettier": "^1.16.4", | ||
"rimraf": "^2.6.3", | ||
"ts-jest": "^24.0.0", | ||
"typescript": "^3.3.3333" | ||
}, | ||
"babel": { | ||
"comments": false, | ||
"presets": [ | ||
[ | ||
"@babel/preset-env", | ||
{ | ||
"targets": { | ||
"node": "10" | ||
} | ||
} | ||
], | ||
"@babel/preset-typescript" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { get } from './' | ||
import { get as _get } from 'lodash' | ||
|
||
describe('get', function() { | ||
type InputType = { | ||
a: string | ||
b?: { | ||
nested?: string | null | ||
} | ||
} | ||
const inputAllPresent: InputType = { | ||
a: 'Value', | ||
b: { | ||
nested: 'Value', | ||
}, | ||
} | ||
const inputOptionalsMissing: InputType = { | ||
a: 'Value', | ||
} | ||
const inputOptionalsSafeAccessMissing: InputType = { | ||
a: 'Value', | ||
b: {} // accessing b.nested will return undefined and will not throw error | ||
} | ||
it('should return value', () => { | ||
const result = get(inputAllPresent, it => it.a) | ||
expect(result).toBe('Value') | ||
}) | ||
it('should return value on existing optional field', () => { | ||
const result = get(inputAllPresent, it => it.b.nested, 'Default') | ||
expect(result).toBe('Value') | ||
}) | ||
it('should return undefined on non existing optional field', () => { | ||
const result = get(inputOptionalsMissing, it => it.b.nested) | ||
expect(result).toBeUndefined() | ||
}) | ||
it('should return defaultValue on non existing optional field', () => { | ||
const result = get(inputOptionalsMissing, it => it.b.nested, 'Default') | ||
expect(result).toBe('Default') | ||
}) | ||
it('should return defaultValue on non existing optional field', () => { | ||
const result = get(inputOptionalsMissing, it => it.b.nested, 'Default') | ||
expect(result).toBe('Default') | ||
}) | ||
|
||
it('should replica lodash interface in cases below', () => { | ||
const result1 = get(inputAllPresent, it => it.a) | ||
const result1_ = _get(inputAllPresent, 'a') | ||
|
||
const result2 = get(inputAllPresent, it => it.b.nested, 'Default') | ||
const result2_ = _get(inputAllPresent, 'b.nested', 'Default') | ||
|
||
const result3 = get(inputOptionalsMissing, it => it.b.nested) | ||
const result3_ = _get(inputOptionalsMissing, 'b.nested') | ||
|
||
const result4 = get(inputOptionalsSafeAccessMissing, it => it.b.nested, 'Default') | ||
const result4_ = _get(inputOptionalsSafeAccessMissing, 'b.nested', 'Default') | ||
|
||
|
||
expect(result1).toBe(result1_) | ||
expect(result2).toBe(result2_) | ||
expect(result3).toBe(result3_) | ||
expect(result4).toBe(result4_) | ||
}) | ||
it('should return undefined and default value in case of null (different from _.get)', function() { | ||
const inputWithNull: InputType = { | ||
a: 'Value', | ||
b: { | ||
nested: null, | ||
}, | ||
} | ||
const defaultedNull = get<InputType, string | null>(inputOptionalsMissing, it => it.b.nested, null) | ||
expect(defaultedNull).toBe(null) | ||
|
||
const undefinedFromNullValue = get(inputWithNull, it => it.b.nested) | ||
expect(undefinedFromNullValue).toBeUndefined() | ||
|
||
const defaultedStringFromNullValue = get(inputWithNull, it => it.b.nested, "Default") | ||
expect(defaultedStringFromNullValue).toBe("Default") | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** Removes all undefined and nulls from the nested types making all nested fields | ||
* non-nullable hence you can simply chain through it and autosuggestion will work | ||
* and will not complain on undefiness and nullability of some of the nested fields | ||
* including the root | ||
* | ||
* @example | ||
* type AllOpt = { | ||
* a?: string | ||
* arr?: string[] | null | ||
* b?: { | ||
* c?: string | undefined | null | ||
* n?: | ||
* | { | ||
* a?: string | null | ||
* b: object | null | ||
* } | ||
* | null | ||
* | undefined | ||
* } | ||
* c?: string | ||
* } | ||
* | ||
* type AllReq = RequireRecursively<AllOpt | undefined | null> | ||
* | ||
* const obj: AllReq = ({} as unknown) as AllReq | ||
* | ||
* obj.b.c // -> string | ||
* obj.b.n.a // -> string | ||
* obj.b.n.b // -> object | ||
* obj.arr // -> string[] | ||
* | ||
* | ||
*/ | ||
export type RequiredRecursively<T> = Exclude< | ||
{ | ||
[P in keyof T]-?: T[P] extends (infer U)[] | ||
? RequiredRecursively<U>[] | ||
: RequiredRecursively<T[P]> | ||
}, | ||
null | undefined | ||
> | ||
|
||
export type AccessorFunction<T, R> = (object: RequiredRecursively<T>) => R | ||
|
||
export function get<T, R>( | ||
object: T, | ||
accessorFn: AccessorFunction<T, R>, | ||
): R | undefined | ||
export function get<T, R>( | ||
object: T, | ||
accessorFn: AccessorFunction<T, R>, | ||
defaultValue: R, | ||
): R | ||
export function get<T, R>( | ||
object: T, | ||
accessorFn: AccessorFunction<T, R>, | ||
defaultValue?: R, | ||
): R | undefined { | ||
try { | ||
const result = accessorFn((object as unknown) as RequiredRecursively<T>) | ||
return result === undefined || result === null ? defaultValue : result | ||
} catch (e) { | ||
return defaultValue === undefined ? undefined : defaultValue | ||
} | ||
} | ||
|
||
export default get |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"compilerOptions": { | ||
"baseUrl": "./src", | ||
"lib": ["es6", "dom", "es2016", "es2017"], | ||
"module": "esnext", | ||
"moduleResolution": "node", | ||
"strict": true, | ||
"outDir": "lib", | ||
"declaration": true, | ||
"esModuleInterop": true, | ||
"sourceMap": true | ||
}, | ||
"exclude": [ | ||
"src/index.test.ts" | ||
] | ||
} |
Oops, something went wrong.