Is it possible to include output parameters in a function with TypeScript?
Something like Func1(string val1, int out k1, int out k2) in C#.
8 Answers
Not currently.
You can return an object that can contain more than one property.
return { k1: 5, k2: 99 };
You can combine this with destructuring so the intermediate object becomes invisible...
function myFunction() {
return { k1: 5, k2: 99 };
}
const { k1, k2 } = myFunction();
console.log(k1);
console.log(k2);
You could also achieve the same with a tuple, but this is pretty readable.
Comments
Here's another way. Define a callback function which will include your out parameters :
function Func1(val1: string, out: (k1: number, k2: number) => void): void {
out(1, 2);
}
Example on how to use it:
function anotherFunction(): void {
let k1: number;
let k2: number;
Func1("something", (v1, v2) => {
k1 = v1;
k2 = v2;
});
console.log(k1); // output: 1
console.log(k2); // output: 2
}
I find it mostly useful for stuff like this:
const keys: string[] = [];
const values: number[] = [];
function tryGet(key: string, out: (value: number) => void): void {
const index = keys.indexOf(key);
if (index >= 0) {
out(values[index]);
}
}
function test(): void {
const key = "myValue";
tryGet(key, (value) => {
console.log(`Key '${key}' exist with value ${value}`);
});
}
Comments
Typescript passes all parameters with "call by value". But if the parameter is a reference this behaves similarly to "call by reference" most of the time. You can write wrapper classes for primitive types. Here's some code:
var func=function(param:Str){
param.str="modified";
}
class Str{
str:string="unmodified";
}
var test:Str=new Str();
alert(test.str); //alerts "unmodified"
func(test);
alert(test.str); //alerts "modified"
You need to be careful, though:
var func=function(param:Str){
param=new Str("modified");
}
class Str{
str:string;
constructor(param:string){
this.str=param;
}
}
var test:Str=new Str("unmodified");
alert(test.str); //alerts "unmodified"
func(test);
alert(test.str); //alerts "unmodified"
The function parameter is passed "call by value". Therefore inside the function body you're working with a copy of a reference. This reference points to the same object as the reference that you passed as a parameter, so you can access its members and modify them. But if you assign a new object to the reference all further changes are applied to this new object. Therefore the code above prints unmodified twice. I think C# works this way, too.
Comments
Generally, you just return an object with multiple properties, one of which contains your function. Something like this:
var foo = function (val1 : string){
// do something
return {
k1: 22,
k2: 33
};
}
You could also make it implement an interface, so you know what to expect as the returned object.
interface IFoo {
(val1: string): INumbers;
}
interface INumbers {
k1 : number;
k2 : number;
}
var foo : IFoo = (val1 : string){
// do something
return {
k1: 22,
k2: 33
};
}
Comments
If you really, really want to have an output parameter, even though you could return an object or an array (as a makeshift tuple object), look at foo and the call site of foo...
function p(s) {
document.body.appendChild(document.createTextNode(s));
document.body.appendChild(document.createElement('BR'));
}
function foo(output: any): void {
output.uno = 1;
output.dos = 2;
}
var o: any = {};
function foo(o);
p(o.uno + " " + o.dos);
Comments
Sometimes the parameter is undefined and you need to instantiate it inside a method. In that cases you can use "lambda functions" or "arrow functions" and simulate the output parameter with this:
example:
class classA
{
propertyA : number;
constructor(value: number){
propertyA = number;
}
}
class classB {
// ...
exampleMethod(){
let classAInstance: classA;
this.sumValueMethod((p) => classAInstance = p, 10);
if(classAInstance != undefined)
alert("Yeah");
}
sumValueMethod(paramA:(p: classA) => any, paramB: number){
let variableA: classA = new classA(0);
variableA.propertyA += paramB;
paramA(variableA);
}
}
Comments
I am still not aware of output parameters in Typescript in 2023.
I want to add that usually it is more elegant to use a method or destructuring of a return value into components.
Assume, we have
function foo(out x, out y, z) {
x = z.x
y = z.y
}
Often, the output parameters are related to the operation or to each other and it makes sense to group and encapsulate them inside an object.
class Foo {
var x; var y;
foo(z) {
x = z.x
y = z.y
}
}
But beware that you don't forget to bind your functions passed as callbacks.
function foo(z) {
return [z.x, z.y]
}
So that you can use
[x, y] = foo(z)
These two methods basically are equivalent in expression to using output parameters. It might be less convenient if you want to apply output parameters as arguments. In this case, a lambda expression or method definition is required.
Cheers!