TypeScript, Promise kullanımını önler, Awaited üzerinde hata verir


Aşağıdaki örnekte, foo fonksiyonunun bir Promise kabul etmesini istemiyorum, ancak diğer herhangi bir tür sorun olmaz.

export {}

function foo<T>(arg: T extends Promise<unknown> ? never : T) {
  console.log(arg);
}

async function bar<T>(arg: Promise<T>) {
  foo(await arg); // Why is this an error?
}

async function baz(arg: Promise<number>) {
  foo(await arg); // OK!
}

foo(await Promise.resolve(1)); // OK

foo(1); // OK

foo(Promise.resolve(1)); // Not OK, as intended

bar fonksiyonunda hata şudur:

Argument of type 'Awaited<T>' is not assignable
to parameter of type 'T extends Promise<unknown> ? never : T'.

T ile Awaited<T> arasındaki fark nedir?

Genel bir tür üzerinde await kullanırken, bunun beklendiği gibi çalışmasını sağlamanın bir yolu var mı?

Cevap #1

Bu tür, eğer T extends Promise<unknown> ise argümanın never türünde olması gerektiğini belirtir. Ancak bar içinde T’nin ne olduğunu bilmiyorsak, foo’ya geçirdiğimiz türün doğru olduğundan emin olamayız.

Başka bir deyişle, teknik olarak bar'a Promise<Promise<any>> türünde bir parametre geçirmek mümkündür; bu durumda T teknik olarak bir Promise'dir.

Ancak, await iç içe geçmiş promise'leri çözer, bu yüzden await sonrası çözülmüş değerin bir Promise olamayacağını biliyoruz. Typescript derleyicisi bunun farkına varamıyor gibi görünüyor.

Yani bu argüman için genel bir tür oluşturabilir ve await'den sonra güvenle dönüştürebilirsiniz.

type NotPromise<T> = T extends Promise<unknown> ? never: T;

function foo<T>(arg: NotPromise<T>) {
  console.log(arg);
}

async function bar<T>(arg: Promise<T>) {
  foo((await arg) as NotPromise<T>);
}

Çalışan örnek: https://stackblitz.com/edit/typescript-h2izuv?file=index.ts