50

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 8

37

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.

Sign up to request clarification or add additional context in comments.

Comments

6

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

4

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

2

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

2

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

0

If you want to mantain C# like syntax you can use:

function func(val1, k1, k2)
{
    k1.v = 7;
    k2.v = 9;
    return "";
}

and to call it

func("", {}, {});   

Comments

0

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

0

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!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.