-
Notifications
You must be signed in to change notification settings - Fork 107
Open
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation
Description
Description
When using newWebSocketRpcSession or newHttpBatchRpcSession with a TypeScript generic parameter, the RpcStub<T> type preserves primitive return types (string, number, boolean) but fails to preserve object/interface return types, returning any instead.
Minimal Reproducible Example
import { newWebSocketRpcSession, type RpcStub } from 'capnweb';
// Define types
type ApiMessage = { message: string; timestamp: string };
// Define API interface
interface MyApi {
getPrimitive(): Promise<string>; // Returns primitive
getObject(): Promise<ApiMessage>; // Returns object
hello(name: string): Promise<ApiMessage>; // Returns object
}
// Create client
const apiStub = newWebSocketRpcSession<MyApi>('wss://example.com/api');
// Primitives work correctly ✅
const primitive = await apiStub.getPrimitive();
// ^? Type is 'string' ✅
// Objects return 'any' ❌
const object = await apiStub.getObject();
// ^? Type is 'any' ❌
const helloResult = await apiStub.hello('world');
// ^? Type is 'any' ❌Expected Behavior
All method return types should be preserved, regardless of whether they're primitives or objects:
const primitive = await apiStub.getPrimitive();
// ^? string ✅
const object = await apiStub.getObject();
// ^? Should be: ApiMessage
const helloResult = await apiStub.hello('world');
// ^? Should be: ApiMessageActual Behavior
Only primitive return types are preserved. Object/interface return types become any:
const apiStub: RpcStub<MyApi> = newWebSocketRpcSession<MyApi>('wss://example.com/api');
// ^? Correctly shows: RpcStub<MyApi>
const primitive = await apiStub.getPrimitive();
// ^? string ✅ Works!
const object = await apiStub.getObject();
// ^? any ❌ Should be ApiMessage
const helloResult = await apiStub.hello('world');
// ^? any ❌ Should be ApiMessage
// No type checking for objects
console.log(helloResult.anythingGoes); // No errorRoot Cause
The RpcStub<T> type definition appears to handle primitives correctly but wraps object return types in complex proxy types (for promise pipelining support) that resolve to any instead of the original type.
Workaround
Manually cast each result:
const helloResult = await apiStub.hello('world') as ApiMessage;
// ^? Now correctly typed as: ApiMessage ✅Environment
- capnweb version: 0.2.0
- TypeScript version: 5.8.3
- Node version: 22.15.1
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation