Here is simple synthetic function
function test(input) {
if (typeof input === 'number') {
return 'a'
} else {
return input
}
}
I want to type it but cannot figure out approach. The best I was able to get is:
function test<T extends number>(input: T): string;
function test<T>(input: T): T;
function test(input) {
if (typeof input === 'number') {
return 'a'
} else {
return input
}
}
const a = [test('2'), test(2), test(null), test(true)] as const
// ^? a: readonly ['2', string, null, true]
// looks valid
const b = [test<string>('2'), test<boolean>(true)] as const
// ^? b: readonly [string, boolean]
// I can control/generalize types!
The blot on the landscape for that solution looks like that:
Parameter 'input' implicitly has an 'any' type.
What am I missing here? How to make Typescript happy while keeping types consistent and reliable?
Each individual overload signature represents a possible variation of parameter types and associated return type for the function. The implementation of the function must recognize all of these possible variations, so the appropriate type for any given parameter in the implementation signature is a union of all of the types used for that parameter in the overload signatures.
Your function has two overload signatures, one with a generic type that is constrained by number
(so input
is expected to be some kind of number type)…
function test<T extends number>(input: T): string;
…and one that uses an unconstrained generic type parameter…
function test<T>(input: T): T;
…which means that it could be any type, and is effectively unknown
.
This means that the type for the input
parameter in the implementation signature should be unknown
(because unknown
absorbs other types in a union) — and you can simply annotate it to satisfy the compiler:
function test<T extends number>(input: T): string;
function test<T>(input: T): T;
function test(input: unknown) {
// ^^^^^^^^^^^^^^
// Annotate the parameter in the implementation signature
if (typeof input === 'number') {
return 'a'
} else {
return input
}
}