Skip to content

Commit 941dbad

Browse files
committed
feat(common): add isGrpcStatusObjectWithCode user-defined type guard
1. User-defined Typescript type-guard function that asserts whether a value or object is a `@grpc/grpc-js` {Partial<StatusObject>} or not. The reason why it checks for {Partial} is because all of the properties of the {StatusObject} are defined as optional for some reason, hence we cannot assume anything about those being present or not by default. 2. Therefore this method will just check if the `code` property is set or not and return `true` or `false` based on that. 3. The above is also the reason why the name of the function is slightly more verbose than your average user-defined type-guard that could be named just "isGrpcStatusObject()" but we wanted to make sure that more specific type-guards can be added later that check for other optional properities or for the presence of all of them together. Link to the status builder within grpc-js: https://github.com/grpc/grpc-node/blob/master/packages/grpc-js/src/status-builder.ts Signed-off-by: Peter Somogyvari <[email protected]>
1 parent 1eacf7e commit 941dbad

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

packages/cactus-common/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"sha3": "2.1.4"
6767
},
6868
"devDependencies": {
69+
"@grpc/grpc-js": "1.10.3",
6970
"@types/json-stable-stringify": "1.0.33",
7071
"@types/sanitize-html": "2.9.5",
7172
"@types/secp256k1": "4.0.3",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { StatusObject } from "@grpc/grpc-js";
2+
3+
/**
4+
* User-defined Typescript type-guard function that asserts whether a value or
5+
* object is a `@grpc/grpc-js` {Partial<StatusObject>} or not.
6+
*
7+
* The reason why it checks for {Partial} is because all of the properties of
8+
* the {StatusObject} are defined as optional for some reason, hence we cannot
9+
* assume anything about those being present or not by default.
10+
* Therefore this method will just check if the `code` property is set or not
11+
* and return `true` or `false` based on that.
12+
*
13+
* The above is also the reason why the name of the function is slightly more
14+
* verbose than your average user-defined type-guard that could be named just
15+
* "isGrpcStatusObject()" but we wanted to make sure that more specific type-guards
16+
* can be added later that check for other optional properities or for the
17+
* presence of all of them together.
18+
*
19+
* @param x Literally any value or object that will be checked at runtime to have
20+
* the `code` property defined as a number.
21+
* @returns `true` if `x` qualifies, `false` otherwise.
22+
*
23+
* @see {StatusObject} of the @grpc/grpc-js library.
24+
*/
25+
export function isGrpcStatusObjectWithCode(
26+
x: unknown,
27+
): x is Partial<StatusObject> {
28+
return (
29+
!!x &&
30+
typeof (x as StatusObject).code === "number" &&
31+
isFinite((x as StatusObject).code)
32+
);
33+
}

packages/cactus-common/src/main/typescript/public-api.ts

+2
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,5 @@ export {
4545
ExpressHttpVerbMethodName,
4646
isExpressHttpVerbMethodName,
4747
} from "./http/express-http-verb-method-name";
48+
49+
export { isGrpcStatusObjectWithCode } from "./grpc/is-grpc-status-object-with-code";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import "jest-extended";
2+
import { isGrpcStatusObjectWithCode } from "../../../../main/typescript";
3+
4+
describe("isGrpcStatusObjectWithCode()", () => {
5+
test("returns true for POJO with correct shape and valid data", () => {
6+
expect(isGrpcStatusObjectWithCode({ code: 1 })).toBeTrue();
7+
expect(isGrpcStatusObjectWithCode({ code: 0 })).toBeTrue();
8+
expect(isGrpcStatusObjectWithCode({ code: -1 })).toBeTrue();
9+
});
10+
11+
test("returns false for POJO with correct shape and invalid data", () => {
12+
expect(isGrpcStatusObjectWithCode({ code: NaN })).toBeFalse();
13+
expect(isGrpcStatusObjectWithCode({ code: "" })).toBeFalse();
14+
expect(isGrpcStatusObjectWithCode({ code: "Hello" })).toBeFalse();
15+
expect(isGrpcStatusObjectWithCode({ code: true })).toBeFalse();
16+
expect(isGrpcStatusObjectWithCode({ code: [] })).toBeFalse();
17+
18+
expect(isGrpcStatusObjectWithCode({ codeX: NaN })).toBeFalse();
19+
expect(isGrpcStatusObjectWithCode({ codeY: "" })).toBeFalse();
20+
expect(isGrpcStatusObjectWithCode({ codeZ: "Hello" })).toBeFalse();
21+
expect(isGrpcStatusObjectWithCode({ codeK: 1 })).toBeFalse();
22+
});
23+
24+
test("returns false for non-POJO input", () => {
25+
expect(isGrpcStatusObjectWithCode(NaN)).toBeFalse();
26+
expect(isGrpcStatusObjectWithCode(null)).toBeFalse();
27+
expect(isGrpcStatusObjectWithCode(undefined)).toBeFalse();
28+
expect(isGrpcStatusObjectWithCode([])).toBeFalse();
29+
expect(isGrpcStatusObjectWithCode(Symbol)).toBeFalse();
30+
});
31+
});

yarn.lock

+1
Original file line numberDiff line numberDiff line change
@@ -7660,6 +7660,7 @@ __metadata:
76607660
version: 0.0.0-use.local
76617661
resolution: "@hyperledger/cactus-common@workspace:packages/cactus-common"
76627662
dependencies:
7663+
"@grpc/grpc-js": "npm:1.10.3"
76637664
"@types/json-stable-stringify": "npm:1.0.33"
76647665
"@types/sanitize-html": "npm:2.9.5"
76657666
"@types/secp256k1": "npm:4.0.3"

0 commit comments

Comments
 (0)