jsii
jsii copied to clipboard
Python: sync vs async return different objects but same type-hint
Describe the bug
The type-hint provided to Python is the same between synchronous requests, and asynchronous requests. However the returned type for a synchronous request is a value-type, but the asynchronous is a reference-type.
Expected Behavior
I would expect the type-hinting to match the actual returned type, and would personally always prefer value-types given I can't work out how to get data from the reference-types.
Current Behavior
The type-hint for sync and async requests is the same, but in actuality one is a value-type and the other is a reference-type.
Reproduction Steps
The TypeScript side looks like this:
export interface Record {
readonly name: string;
}
export class RecordFactory {
public makeRecord(): Record {
return {
name: "Record A"
}
}
public async makeRecordAsync(): Promise<Record> {
return new Promise(res => {
setTimeout(() => {
res({
name: "Record B"
})
}, 1000);
});
}
}
The Python side looks like this:
record_factory = RecordFactory()
record = record_factory.make_record()
record_async = record_factory.make_record_async()
print(record.name)
print(record_async.name)
This would throw an error on the second print because record_async.name
does not exist, because record_async
is a reference-type.
The generated Python library looks like this:
class RecordFactory(metaclass=jsii.JSIIMeta, jsii_type="jsii-test.RecordFactory"):
def __init__(self) -> None:
jsii.create(self.__class__, self, [])
@jsii.member(jsii_name="makeRecord")
def make_record(self) -> Record:
return typing.cast(Record, jsii.invoke(self, "makeRecord", []))
@jsii.member(jsii_name="makeRecordAsync")
def make_record_async(self) -> Record:
return typing.cast(Record, jsii.ainvoke(self, "makeRecordAsync", []))
Possible Solution
I'm just investigating JSII as a solution for an issue we have, so don't know what the solution is here. What I can say is this is confusing for a new user. The way I see it either the return type for the async
function should be either swapped to show the reference type, or better yet (IMHO) could correctly cast to a value-type.
Additional Information/Context
No response
SDK version used
1.61.0
Environment details (OS name and version, etc.)
Mac-OS, Node 17, TS 3.9.10
I have checked the dotNet generated package as well which worked as expected:
var recordFactory = new RecordFactory();
var record = recordFactory.MakeRecord();
var recordAsync = recordFactory.MakeRecordAsync();
Console.WriteLine($"Sync-record: {record.Name}");
Console.WriteLine($"Async-record: {recordAsync.Name}");
Output:
Sync-record: Record A
Async-record: Record B
Additionally, if I return as a Promise<any>
it correctly works as an async but doesn't have type-hinting.
Ah - I guess the compiler & doc should call this out clearly, but async
support is largely untested and not very uniformly implemented... we never really had a clear use-case for this, and async/await semantics aren't available consistently in our target runtimes, which creates additional headaches in figuring out how to consistently represent...
I believe the .NET solution "works", although it most likely runs pseudo-synchronously, in fact...
I'd be inclined to actually fix that (granted you appear to have a use-case), but I'm afraid it might take a while before we can prioritize this specifically.
⚠️COMMENT VISIBILITY WARNING⚠️
Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.