Ron
Ron

Reputation: 6735

Overload generic functions with the first generic type not in parameters

I got a problem when using generic overload functions like below (playground).

The generic type T1 is not used in the parameters (just used in return type), so when I try to use overload #2, I have to provide all the types like f<string, string>('123') which sometimes is not possible. Is there a way to let f<string>('123') match overload #2?

function f<T1, T2>(t2: T2): T1
function f<T1>(): T1

function f<T1, T2>(t2?: T2): T1 | void {
}

f<string, string>('123') // ok
f<string>()              // ok
f<string>('123')         // error here, can we fix it by not using f<string, string>('123') ?

function f<T1, T2>(t2: T2): T1
function f<T1>(): T1

function f<T1, T2>(t2?: T2): T1 | void {
}

f < string, {id: number}>({id: 123})  // ok
f<string>()                           // ok
f<string>({id:123})                   // typescript complain here can we fix it by not using f<string, string>({id:123}) ?

playground

Upvotes: 4

Views: 87

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249476

You can use a default for the type parameter, if you want T2 to be the same as T1 you can use T1 as the default:

function f<T1>(): T1
function f<T1, T2 extends T1 = T1>(t2: T2): T1
function f<T1, T2>(t2?: T2): T1 | void {
}

f<string, string>('123') // ok
f<string>()              // ok
f<string>('123')         // OK

f<number>(123)         // OK

I would like to raise a different question though. Why have T2 at all id you don't want to specify it and just default it to T1. Why not just use T1. Type parameters that only appear in one position (either return type or a parameter type) are usually suspect. The whole point of type parameters is to establish relations between parameters or between parameters and return type.

Without knowing your full use case, this function makes more sense to me:


function f<T1>(): T1
function f<T1>(t2: T1): T1
function f<T1>(t2?: T1): T1 | void {
}

f<string>()              // ok
f('123')         // OK

f(123)         // OK

Upvotes: 1

Mor Shemesh
Mor Shemesh

Reputation: 2890

You can add a fallback for T2 to unknown or any:

function f<T1, T2 = unknown>(t2: T2): T1
function f<T1>(): T1

function f<T1, T2>(t2?: T2): T1 | void {
}

Or simply have one declaration for all the cases:

function f<T1, T2 = unknown>(t2?: T2): T1 | void {
}
// or
function f<T1, T2 = any>(t2?: T2): T1 | void {
}

Upvotes: 2

Related Questions