TypeScript - Genel tipe dayalı koşullu yöntem parametreleri


Yeni bir TypeScript sınıfı yazma sürecindeyim; bu sınıf, bir fonksiyonun girdisi olarak kullanılacak olan genel bir değeri alıyor. Eğer bir değer verilmezse, fonksiyon herhangi bir girdi almamalıdır.

İdeali sınıfın bu şekilde aşırı yüklenmiş olması olurdu.

class Emitter<T = void> {
    public activate(): void // When T is void
    public activate(arg: T): void // When T isn't void
    public activate(arg?: T) { /* ... */ }
}

Yöntemin bir işlev özelliği olması teoride işe yarar ancak yöntemin uygulanmasında bir @ts-ignore gerektirir.

type OneArgFn<T> = T extends void
    ? () => void
    : (arg: T) => void

interface Emitter<T> {
    readonly activate: OneArgFn<T>
}

Başka bir olasılık, bir Generic sağlandığında veya sağlanmadığında farklı bir yapıcıyı dışa aktarmaktır, örneğin aşağıdaki gibi

interface EmitterNoArg extends Emitter {
    activate: () => true
}
interface EmitterOneArg<T> extends Emitter<T> {
    activate: (arg: T) => void
}

interface EmitterConstructor {
    new(): Emitter

    new(): EmitterNoArg
    new<T>(): EmitterOneArg<T>
}

ama sonra bunu dışa aktarmak için unknown anahtar kelimesi gereklidir.

export default Emitter as unknown as EmitterConstructor

Bunlar optimal gibi görünmüyor. Genel tipin türüne dayalı koşullu argümanlara sahip olmanın uygun bir yolu var mı? TypeScript’in yeni koşullu tiplerinin bu sorunu çözeceğini düşünüyorum.

Cevap #1

Bunu yapmanın bir yolu, ayrı bir açık imzada rest parametrelerinde demetler kullanmak olurdu:

type OneArgFn<T> = T extends void
    ? () => void
    : (arg: T) => void

class Emitter<T = void> {
    public activate(...a: Parameters<OneArgFn<T>>): void
    public activate(arg?: T) { /* ... */ }
}

new Emitter().activate();
new Emitter<string>().activate("") // in 3.4 argument names are preserved

İlgili makaleler