I\'m using TypeScript with the MongoDB node.js driver. Note, this is not a Mongo question, its just the particular use case of this issue I\'m having.
Pretty much ev
I was wrong, this doesn't work in C# either. Here's the example of the same code from TypeScript, written in C#, that does not work:
using System.IO;
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
var task = Wrapper(cb => FakeMongoFunctionWithCallback(5, cb));
}
static void FakeMongoFunctionWithCallback(int arg, Action<Exception, int> callback)
{
// just pass through the arg into the callback, pretending we went to a db and came back with that result
callback(null, arg);
}
static Task<T> Wrapper<T>(Action<Action<Exception, T>> action) {
var tcs = new TaskCompletionSource<T>();
action((err, res) => {
if (err != null) tcs.SetException(err);
else tcs.SetResult(res);
});
return tcs.Task;
}
}
Typescript is able to infer the type of some generic functions but it has some limitations.
Since there isn't any information in the generic section of the handbook I decided to make some tests and see where it breaks down.
function genericFunction<T>(value: T): T {
return value;
}
// type of val is Window
let val = genericFunction(window);
This works, there's no need to specify the type of T manually.
function genericFunction2<T>(value: T, anotherValue: T) : T {
return value;
}
// type of val is String
let val = genericFunction2("b", "5");
// compilation error type of T can't be inferred from usage
let anotherVal = genericFunction2("b", 5);
This works, there's no need to specify the type of T manually.
function callBackAndValue<T>(action: (value: T) => T, value: T): T {
return action(value);
}
// type of val is string
let val = callBackAndValue((value: string) => value + "5", "abc ");
This works, there's no need to specify the type of T manually.
function callBackAndValueWithPromise<T>(action: (value: T) => T, value: T): Promise<T> {
return new Promise<T>((resolve, reject) => {
resolve(action(value));
});
}
// type of val is Promise<string>
let val = callBackAndValueWithPromise((value: string) => value + "5", "abc ");
This works, there's no need to specify the type of T manually.
function onlyCallback<T>(action: () => T) : T {
return action();
}
// type of val is string
let val = onlyCallback(()=> "abc");
This works, there's no need to specify the type of T manually.
function onlyCallbackWithPromise<T>(action: () => T): Promise<T> {
return new Promise<T>((resolve, reject) => {
resolve(action());
});
}
// the type of val is Promise<string>
let val = onlyCallbackWithPromise(()=> "abc");
This works, there's no need to specify the type of T manually.
function typeFromCallbackOfCallback<T>(action: (callback: (value: T) => void) => void): Promise<T> {
return new Promise<T>((resolve, reject) => {
action((value) => {
resolve(value);
});
});
}
// here the compiler fails to infer the type cb should take as a parameter and it seems to default to object({})
// type of Val is Promise<{}>
let val = typeFromCallbackOfCallback(cb => cb("abc"));
This no longer works and needs the type to be specified manually.
Since the compiler is limited at the moment I guess you are stuck having to specify the type for this case. That is the solution given in the handbook as well for the cases when type inference fails.
Adding another parameter of type T fixes it, but It doesn't quite match your case.
function lastOne<T>(action: (callback: (value: T) => void) => void, b: T): Promise<T> {
return new Promise<T>((resolve, reject) => {
action((value) => {
resolve(value);
});
});
}
// type of var is Promise<string>
let var = lastOne(cb => cb("abc"), "a");
This works, there's no need to specify the type of T manually.