Çıkarılan Parametreleri, bir TypeScript fonksiyonunu çağırmak için kullanılan türlere nasıl bağlarsınız?


TL;DR - Bu oyun alanı bağlantısındaki hatayı @ts-expect-error'e başvurmadan nasıl kaldırabilirim?

Uzak bir API tanımladığımızı hayal edin...

const api = {
  str2num(_arg: string) { return 42; },
  num2str(_arg: number) { return 'forty-two'; },
};

type API = typeof api;
type APIFuncName = keyof API;
type Func<FN extends APIFuncName> = API[FN];

export function exec<FN extends APIFuncName>(
  name: FN,
  ...args: Parameters<Func<FN>>
) {
  // Unexpected error:
  // "A spread argument must either have a tuple type or be passed to a rest parameter."
  return api[name](...args);
}

// This is fine
console.log(exec('str2num', 'zero'));
console.log(exec('num2str', 0));

// An error as expected: Type 'number' is not assignable to type 'string'
// console.log(exec('str2num', 0));

Biz exec(...) fonksiyonunu gayet iyi bir şekilde kullanabiliyoruz, ancak TypeScript exec(...) uygulaması hakkında beklenmedik bir şekilde şikayet ediyor.

Bence sorun, TypeScript'in args türünü api[name] parametreleriyle ilişkilendirememesi.

Hata mesajı biraz kafa karıştırıcıdır ("Bir spread argümanı ya bir tuple tipi olmalı ya da bir rest parametresine geçirilmelidir.") çünkü args açıkça zaten bir tuple tipine sahiptir.

Bunu @ts-expect-error kullanmadan doğru şekilde nasıl yazabilirim?

Cevap #1

Buna bir çözüm buldum, ama biraz hileli; temelde gerçek fonksiyon çağrısını yapmak için bir yardımcı fonksiyon yazabilirsiniz, burada fonksiyon, argümanları bir rest parametresi olarak kabul edecek şekilde türlendirilmiş. Bu, hata mesajındaki “... veya bir rest parametresine geçirilmek” kısmını karşılıyor. Zarif bir çözüm olup olmadığından emin değilim.

export function exec<FN extends APIFuncName>(
  name: FN,
  ...args: Parameters<Func<FN>>
) {
  return callHelper(api[name], args);
}

function callHelper<F extends (...args: any[]) => any>(
  f: F,
  args: Parameters<F>
): ReturnType<F> {
  return f(...args);
}

Oyun Alanı Bağlantısı