Skip to content

Commit 0bf45f8

Browse files
authored
Merge pull request #64 from shiftcode/#62-add-object-utilities
#62 add object utilities
2 parents 4162b15 + 7ded7bd commit 0bf45f8

8 files changed

+105
-6
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/logger/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@shiftcode/logger",
3-
"version": "3.0.1",
3+
"version": "3.0.2-pr62.0",
44
"description": "logger for local and aws lambda execution",
55
"repository": "https://github.com/shiftcode/sc-commons-public",
66
"license": "UNLICENSED",
@@ -37,7 +37,7 @@
3737
"test:watch": "npm run test -- --watch"
3838
},
3939
"devDependencies": {
40-
"@shiftcode/utilities": "^4.1.0"
40+
"@shiftcode/utilities": "^4.2.0-pr62.0"
4141
},
4242
"peerDependencies": {
4343
"@shiftcode/utilities": "^4.0.0 || ^4.0.0-pr53"

packages/utilities/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@shiftcode/utilities",
3-
"version": "4.1.0",
3+
"version": "4.2.0-pr62.0",
44
"description": "Contains some utilities",
55
"repository": "https://github.com/shiftcode/sc-commons-public",
66
"license": "MIT",

packages/utilities/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ export * from './lib/group-by/group-by.js'
77
export * from './lib/http/http-constants.js'
88
export * from './lib/json-stringify-replacer/json-stringify-replacer.function.js'
99
export * from './lib/map-values-deep/map-values-deep.js'
10+
export * from './lib/object/get-value-assert-defined.function.js'
1011
export * from './lib/object/omit-props.function.js'
1112
export * from './lib/object/pick-props.function.js'
13+
export * from './lib/object/pick-props-assert-defined.function.js'
1214
export * from './lib/promise/make-deferred.function.js'
1315
export * from './lib/math/clamp.function.js'
1416
export * from './lib/math/random-int.js'
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { getValueAssertDefined } from './get-value-assert-defined.function.js'
2+
3+
describe('getValueAssertDefined', () => {
4+
interface Test {
5+
x: string | null
6+
y?: boolean
7+
z: number | undefined
8+
}
9+
10+
describe('throws when not defined', () => {
11+
const empty: Test = { x: null, z: undefined }
12+
13+
test('when null', () => {
14+
expect(() => getValueAssertDefined(empty, 'x')).toThrow()
15+
})
16+
17+
test('when undefined', () => {
18+
expect(() => getValueAssertDefined(empty, 'z')).toThrow()
19+
})
20+
21+
test('when optional', () => {
22+
expect(() => getValueAssertDefined(empty, 'y')).toThrow()
23+
})
24+
})
25+
26+
describe('returns value when defined', () => {
27+
const obj: Test = {
28+
x: '',
29+
y: false,
30+
z: 0,
31+
}
32+
33+
test('when empty string', () => {
34+
expect(getValueAssertDefined(obj, 'x')).toEqual('')
35+
})
36+
test('when false', () => {
37+
expect(getValueAssertDefined(obj, 'y')).toEqual(false)
38+
})
39+
test('when zero', () => {
40+
expect(getValueAssertDefined(obj, 'z')).toEqual(0)
41+
})
42+
43+
test('makes it type safe', () => {
44+
const tDefined: { num: number | null } = { num: 42 }
45+
// assign to variable to ensure type safety
46+
const res: number = getValueAssertDefined(tDefined, 'num')
47+
expect(res).toEqual(42)
48+
})
49+
})
50+
})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { isDefined } from '../ts-guards/is-defined.js'
2+
3+
/**
4+
* returns the value of the provided key on given object. throws if the value is null or undefined
5+
*/
6+
export function getValueAssertDefined<T, K extends keyof T>(obj: T, key: K): NonNullable<T[K]> {
7+
type X = NonNullable<T[K]>
8+
const value: X | null | undefined = <any>obj[key]
9+
10+
if (!isDefined(value)) {
11+
throw new Error(`Expected property "${String(key)}" to be defined. Was "${value}" instead`)
12+
}
13+
return value
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { pickPropsAssertDefined } from './pick-props-assert-defined.function.js'
2+
3+
describe('pickPropsAssertDefined', () => {
4+
test('returns object with picked props', () => {
5+
const obj = { a: true, b: 'foo', c: 42 }
6+
expect(pickPropsAssertDefined(obj, ['a', 'c'])).toEqual({ a: true, c: 42 })
7+
})
8+
test('throws when picked prop values are null or undefined', () => {
9+
const obj = { a: 'ok', b: null }
10+
expect(() => pickPropsAssertDefined(obj, ['a', 'b'])).toThrow(Error)
11+
})
12+
})
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { isDefined } from '../ts-guards/is-defined.js'
2+
3+
export type PickedPropsDefined<T, K extends keyof T> = {
4+
[key in K]-?: NonNullable<T[key]>
5+
}
6+
7+
/**
8+
* returns an object containing the provided props with their respective value. throws if their value is null or undefined
9+
*/
10+
export function pickPropsAssertDefined<T, TProp extends keyof T>(
11+
obj: T,
12+
props: readonly TProp[],
13+
): PickedPropsDefined<T, TProp> {
14+
const entries = props.map((p) => {
15+
if (!isDefined(obj[p])) {
16+
throw new Error(`Expected property "${String(p)}" to be defined. Was "${String(obj[p])}" instead`)
17+
}
18+
return [p, obj[p]]
19+
})
20+
return Object.fromEntries(entries)
21+
}

0 commit comments

Comments
 (0)