Reputation: 1699
Is it possible to declare typing for a Typescript function with the following behavior:
declare const fun: HowToTypeThis
export const string_or_number_fun = fun<
'num', number,
'str', string
>()
string_or_number_fun should accept
either
string_or_number_fun('str', string)
or
string_or_number_fun('num', number)
string_or_number_fun('str', '')
string_or_number_fun('num', 12)
My attempts led me to this:
interface HowToTypeThis {
<Name1 extends string, Type1,
Name2 extends string, Type2>(): <N = Name1 | Name2>(_: N, __: N extends Name1
? Type1
: N extends Name2
? Type2
: never): any
}
TS compiler reports string_or_number_fun as of type:
const string_or_number_fun:
<N = "num" | "str">(_: N, __: N extends "num" ? number : N extends "str" ? string : never) => any
and it looks ok
but i get :
[ts] Argument of type '""' is not assignable to parameter of type 'never'. [2345]
and
[ts] Argument of type '12' is not assignable to parameter of type 'never'. [2345]
and it doesn't either guard from typing an unexpected string as first argument
Upvotes: 2
Views: 65
Reputation: 51579
There must be a constraint for N
type parameter, otherwise it will be widened to string
, resulting in never
coming from a conditional type.
N extends Name1 | Name2
is the only missing part in your code:
interface HowToTypeThis {
<Name1 extends string, Type1,
Name2 extends string, Type2>(): <N extends Name1 | Name2 = Name1 | Name2>(_: N, __: N extends Name1
? Type1
: N extends Name2
? Type2
: never) => any
}
Upvotes: 1
Reputation: 7542
You can achieve what you are looking for by first declaring a mapping of your custom type names to the type that it represents and then using that as part of your function declaration. Something like:
interface TypeNameToType {
num: number;
str: string;
}
function fun<T extends keyof TypeNameToType>(type: T, value: TypeNameToType[T])
{
return value;
}
Now if you try and call fun('num', 'thisisastring');
Typescript will get mad that you used 'num'
but the second param is not a number.
Upvotes: 2