Here is the code: (question follows)
one file contains this (types.ts)
declare global{
interface AnInterface{
}
}
export type SomeType<T> =
T extends [infer A, infer B] ?
(fst: A, snd:B) => Promise<B>
: never
export async function accept<Z extends keyof AnInterface>(aKey: Z, fn : SomeType<Parameters<AnInterface[Z]>>){
//do sthg with fn
const firstArg : any = 1;
const secondArg : any = 2;
const fnAsAny = <any>fn;
const result = await fnAsAny(firstArg,secondArg);
console.log(result)
}
and in another file ("consumer.ts")
import {accept} from './types';
declare global{
interface AnInterface{
one : typeof fone
two : typeof ftwo
three : typeof fthree
four : typeof ffour
}
}
export async function fone(a:number, b:number){return a+b;}
export async function ftwo(a:any, b:string){return a+b;}
export async function fthree(a:string, b:number=1){return b;}
export async function ffour(a:string){}
a: accept("one", fone); // OK
b: accept("two", fone); // ERROR BUT ... is expected: Argument of type '(a: number, b: string) => Promise<string>' is not assignable to parameter of type '(fst: string, snd: string) => Promise<string>'.
c: accept("two", ftwo); // OK
d: accept("three", fthree); // Argument of type '(a: string, b?: number) => Promise<number>' is not assignable to parameter of type 'never'.
e: accept("four", ffour); // Compile Error but would like to pass
I would like to define type SomeType<T>
so that line labeled d and e would pass the typescript check. Is this possible? problem I have is with optional parameter, for case e , I could add another conditional type check.
Typescript: v 4.1
I've got a simple definition that works for all of your cases, with a small caveat regarding ffour
.
We want a function that takes up to two arguments. The second argument could be optional or could be omitted entirely. The function returns a Promise
of the type of the second argument.
type MyFunc<A, B> = (a: A, b: B) => Promise<B>;
In the type itself, we state that B
is required. This is because a function with optional arguments extends
one with required arguments, but not the other way around. If B
were optional in the type, then we could never fulfill that contract with a function that had a required second argument.
Note that a function with 0 arguments would pass because it's okay to have a function with less arguments than expected, but not more.
We make a dummy function which does nothing to see if our test cases will be accepted as arguments.
const checkFunc = <A, B>(func: MyFunc<A, B>): void => {}
// pass with 2 required args
checkFunc(
async (a: number, b: number) => a + b
);
// pass with 2 requied args of different types
checkFunc(
async (a: any, b: string) => a + b
);
// pass with optional second argument
checkFunc(
async (a: string, b: number = 1) => b
);
// FAIL as expected with more than 2 arguments
checkFunc(
async (a: number, b: number, c: number) => a + b + c
)
If there is no second argument, then what is our return type? Can it be any
-- since we could call the function with any ignored second argument -- or can it only ever be undefined
? This is a question of expected behavior so there is no right or wrong answer.
As currently written, single-argument function will pass with any
return type as the value of the second argument is unknown
.
// pass with void function of single argument
checkFunc (
async (a: string) => {}
)
// pass with function of single argument returning a value
checkFunc (
async (a: string) => a
)
However we can change the signature of the function to enforce that only void
/ undefined
can be returned.
// FAIL when returning a value with second argument explicitly disallowed
checkFunc (
async (a: string, b?: never) => a
)
We can also force failure by explicitly setting the generics of checkFunc
rather than allowing them to be inferred.
// FAIL based on generics <string, never> -- must have <string, string> to pass
checkFunc<string, never> (
async (a: string) => a
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.