javascript - Finns det ett sätt att använda ReturnType inuti en funktion och referera till funktionen utan att använda dess namn?


Kort sagt, jag vet att jag kan göra detta:

function my_function() : Error {
  return some_generic_function<ReturnType<typeof my_function>>();
}

Men finns det ett sätt att använda något som this-nyckelordet för att referera till funktionen som innehåller anropet, men utan att använda dess namn? Som:

function my_function() : Error {
  //This does not work, ofc
  return some_generic_function<ReturnType<typeof this>>();
}

Mer kontext:

Jag har flera service-liknande funktioner som alla returnerar ett Promise med samma mönster av resolve/reject. Därför har jag gjort en generell funktion och vill kunna använda den i varje av mina service-liknande funktioner.

function my_generic_return<T> (data?:T, error?: Error): Promise<T> {
  return new Promise((resolve, reject) => {
    if (typeof data !== 'undefined') {
      return resolve(data);
    }
    return reject();
  });
}

function service1() : Promise<type1> {
  const data : type1 | undefined ...
  // ...
  // But this line is kinda ugly
  return my_generic_return<ReturnType<typeof service1>>()
}

function service2() : Promise<type2> {
  const data : type2 | undefined ...
  // ...
  // But this line is kinda ugly
  return my_generic_return<ReturnType<typeof service2>>()
}

Ett sätt jag skulle vilja ändra den returvärdet är att ha något generiskt istället för namnet på funktionen inuti ReturnType<typeof function_name>

Lösning:

@captain-yossarians svar är utmärkt. Jag låter TypeScript härleda mina typer. Här är min kod:

function my_generic_return<T>(data?: NonNullable<T>, error?: Error)
  : Promise<NonNullable<T>> {
  // I use NonNullable since I never return a Promise with an undefined object.
  return new Promise((resolve, reject) => {
    if (typeof data !== 'undefined') {
      return resolve(data);
    }
    if (error instanceof Error) {
      return reject(error)
    }
    return reject(new Error("Unknown error");
  });
}


function service1() {
  const data : type1 | undefined = undefined

  // We may set data here...
 
  return my_generic_return(data)
}

function service2() {
  const data : type2 | undefined = undefined
  
  // We may set data here...
  
  return my_generic_return(data)
}

const global_data: type2 = new type2();
service2.then(
      // Param correctly seen as 'type2'
      // This is why I used NonNullable in the generic
      // Otherwise it would be seens as 'type2 | undefined'
      // because that's the type of data inside service2
      (data) => {
        global_data = data
      }
    );

Svar #1

Tekniskt sett är det möjligt. some_generic_function bör förvänta sig en generisk parameter.

const foo = <T,>() => null as any

function my_function(): Error {
  return foo<ReturnType<typeof my_function>>();
}

Men jag är inte säker på om det är ett bra sätt att gå.

Du skickar en explicit generisk parameter till foo inuti my_function men du använder den inte alls. Det skulle vara bättre om du delade lite mer kontext.

UPPDATERING

Tumregel: i 80% av fallen bör du inte använda explicita generics när du anropar en funktion. TS bör kunna härleda det.

Tänk på nästa exempel:

function my_generic_return<T>(data?: T, error?: Error): Promise<T> {
  return new Promise((resolve, reject) => {
    if (typeof data !== 'undefined') {
      return resolve(data);
    }
    return reject();
  });
}

type Foo = {
  tag: 'foo'
}
function service1<T>(data: T) {

  return my_generic_return(data)
}

// return type is Promise<Foo>
function service2() {
  const data: Foo = null as any

  return my_generic_return(data)
}