Skip to content

Commit 030c0b6

Browse files
authored
Enable strictFunctionTypes (#1047)
1 parent 53553d6 commit 030c0b6

File tree

7 files changed

+49
-23
lines changed

7 files changed

+49
-23
lines changed

src/core/Service.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
import { EventEmitter } from "eventemitter3";
77
import type {
8-
RosbridgeCallServiceMessage,
8+
RosbridgeMessage,
99
RosbridgeServiceResponseMessage,
1010
} from "../types/protocol.ts";
11-
import { isRosbridgeServiceResponseMessage } from "../types/protocol.ts";
11+
import {
12+
isRosbridgeCallServiceMessage,
13+
isRosbridgeServiceResponseMessage,
14+
} from "../types/protocol.ts";
1215
import type Ros from "./Ros.js";
1316
import { v4 as uuidv4 } from "uuid";
1417

@@ -19,9 +22,8 @@ export default class Service<TRequest, TResponse> extends EventEmitter {
1922
/**
2023
* Stores a reference to the most recent service callback advertised so it can be removed from the EventEmitter during un-advertisement
2124
*/
22-
#serviceCallback:
23-
| ((rosbridgeRequest: RosbridgeCallServiceMessage<TRequest>) => void)
24-
| null = null;
25+
#serviceCallback: ((rosbridgeRequest: RosbridgeMessage) => void) | null =
26+
null;
2527
isAdvertised = false;
2628
/**
2729
* Queue for serializing advertise/unadvertise operations to prevent race conditions
@@ -118,6 +120,11 @@ export default class Service<TRequest, TResponse> extends EventEmitter {
118120

119121
// Store the new callback for removal during un-advertisement
120122
this.#serviceCallback = (rosbridgeRequest) => {
123+
if (!isRosbridgeCallServiceMessage<TRequest>(rosbridgeRequest)) {
124+
throw new Error(
125+
`Invalid message received on service channel: ${JSON.stringify(rosbridgeRequest)}`,
126+
);
127+
}
121128
const response = {};
122129
let success: boolean;
123130
try {
@@ -227,6 +234,11 @@ export default class Service<TRequest, TResponse> extends EventEmitter {
227234
}
228235

229236
this.#serviceCallback = (rosbridgeRequest) => {
237+
if (!isRosbridgeCallServiceMessage<TRequest>(rosbridgeRequest)) {
238+
throw new Error(
239+
`Invalid message received on service channel: ${JSON.stringify(rosbridgeRequest)}`,
240+
);
241+
}
230242
(async () => {
231243
try {
232244
this.ros.callOnConnection({

src/core/SocketAdapter.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export default class SocketAdapter {
6565
}: {
6666
onOpen: (event: Event) => void;
6767
onClose: (event: Event) => void;
68-
onError: (event: ErrorEvent) => void;
68+
onError: (event: ErrorEvent | RTCErrorEvent) => void;
6969
onMessage: (message: RosbridgeMessage) => void;
7070
decoder?: ((data, callback: (error, result) => void) => void) | null;
7171
},
@@ -82,7 +82,7 @@ export default class SocketAdapter {
8282
this.socket.onclose = (e: Event) => {
8383
onClose(e);
8484
};
85-
this.socket.onerror = (e: ErrorEvent) => {
85+
this.socket.onerror = (e: ErrorEvent | RTCErrorEvent) => {
8686
onError(e);
8787
};
8888
this.socket.onmessage = (e: MessageEvent) => {
@@ -157,18 +157,25 @@ export default class SocketAdapter {
157157
callback: (message: RosbridgeMessage) => void,
158158
) {
159159
if (isRosbridgePngMessage(message)) {
160+
const pngCallback = (data: unknown) => {
161+
if (isRosbridgeMessage(data)) {
162+
callback(data);
163+
} else {
164+
throw new Error("Decompressed PNG data was invalid!");
165+
}
166+
};
160167
// If in Node.js..
161168
if (typeof window === "undefined") {
162169
import("../util/decompressPng.js")
163170
.then(({ default: decompressPng }) => {
164-
decompressPng(message.data, callback);
171+
decompressPng(message.data, pngCallback);
165172
})
166173
.catch(console.error);
167174
} else {
168175
// if in browser..
169176
import("../util/shim/decompressPng.js")
170177
.then(({ default: decompressPng }) => {
171-
decompressPng(message.data, callback);
178+
decompressPng(message.data, pngCallback);
172179
})
173180
.catch(console.error);
174181
}

src/core/Topic.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import { EventEmitter } from "eventemitter3";
77
import Service from "./Service.js";
88
import type Ros from "./Ros.js";
9-
import type {
10-
RosbridgeAdvertiseMessage,
11-
RosbridgePublishMessage,
12-
RosbridgeSubscribeMessage,
9+
import {
10+
isRosbridgePublishMessage,
11+
type RosbridgeAdvertiseMessage,
12+
type RosbridgeMessage,
13+
type RosbridgeSubscribeMessage,
1314
} from "../types/protocol.ts";
1415
import type { rosapi } from "../types/rosapi.ts";
1516
import { v4 as uuidv4 } from "uuid";
@@ -138,8 +139,14 @@ export default class Topic<T> extends EventEmitter<{
138139
}
139140
}
140141

141-
#messageCallback = (data: RosbridgePublishMessage<T>) => {
142-
this.emit("message", data.msg);
142+
#messageCallback = (data: RosbridgeMessage) => {
143+
if (isRosbridgePublishMessage<T>(data)) {
144+
this.emit("message", data.msg);
145+
} else {
146+
throw new Error(
147+
`Unexpected message on topic channel: ${JSON.stringify(data)}`,
148+
);
149+
}
143150
};
144151
/**
145152
* Every time a message is published for the given topic, the callback

src/tf/ROS2TFClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export default class ROS2TFClient extends BaseTFClient {
99
goal_id: string;
1010
actionClient: Action<
1111
tf2_web_republisher.TFSubscriptionGoal,
12-
tf2_web_republisher.TFSubscriptionResult,
13-
tf2_web_republisher.TFSubscriptionFeedback
12+
tf2_web_republisher.TFSubscriptionFeedback,
13+
tf2_web_republisher.TFSubscriptionResult
1414
>;
1515
currentGoal?: tf2_web_republisher.TFSubscriptionGoal;
1616

src/types/cbor-js.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
declare module "cbor-js" {
22
function decode(
33
data: ArrayBufferLike,
4-
tagger: (data: Uint8Array, tag: number) => unknown,
4+
tagger: (data: Uint8Array<ArrayBuffer>, tag: number) => unknown,
55
): unknown;
66
}

src/types/protocol.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ export interface RosbridgePublishMessage<TMessage = unknown>
8888
msg: TMessage;
8989
}
9090

91-
export function isRosbridgePublishMessage(
91+
export function isRosbridgePublishMessage<T>(
9292
message: RosbridgeMessage,
93-
): message is RosbridgePublishMessage {
93+
): message is RosbridgePublishMessage<T> {
9494
return message.op === "publish";
9595
}
9696

@@ -161,9 +161,9 @@ export interface RosbridgeCallServiceMessage<TArgs = undefined>
161161
timeout?: number;
162162
}
163163

164-
export function isRosbridgeCallServiceMessage(
164+
export function isRosbridgeCallServiceMessage<T>(
165165
message: RosbridgeMessage,
166-
): message is RosbridgeCallServiceMessage {
166+
): message is RosbridgeCallServiceMessage<T> {
167167
return message.op === "call_service";
168168
}
169169

tsconfig.build.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@
4141
"strictBindCallApply": true /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */,
4242
"strictBuiltinIteratorReturn": true /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */,
4343
"useUnknownInCatchVariables": true /* Default catch clause variables as `unknown` instead of `any`. */,
44+
"strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */,
4445
"strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */,
4546
"noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */,
4647

4748
/* Rules to be enabled */
4849
"exactOptionalPropertyTypes": false /* Differentiate between undefined and not present when type checking */,
4950
"noImplicitAny": false /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
5051
"noUncheckedIndexedAccess": false /* Add `undefined` to a type when accessed using an index. */,
51-
"strictFunctionTypes": false /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */,
5252

5353
"types": ["@types/node"]
5454
},

0 commit comments

Comments
 (0)