代码如下: (问题如下)
一个文件包含这个(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)
}
并在另一个文件(“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
我想定义类型 SomeType<T>
以便标记为 d 和 e 的行将通过打字稿检查。
这可能吗?我遇到的问题是可选参数,对于 case e,我可以添加另一个条件类型检查。
打字稿:v 4.1
答案 0 :(得分:0)
我有一个适用于您的所有情况的简单定义,还有一个关于 ffour
的小警告。
我们想要一个最多接受两个参数的函数。第二个参数可以是可选的,也可以完全省略。该函数返回第二个参数类型的 Promise
。
type MyFunc<A, B> = (a: A, b: B) => Promise<B>;
在类型本身中,我们声明 B
是必需的。这是因为带有可选参数 extends
的函数带有必需参数,但反之则不然。如果 B
在类型中是可选的,那么我们永远无法使用具有必需的第二个参数的函数来实现该契约。
请注意,参数为 0 的函数会通过,因为参数少于预期的函数是可以的,但不能更多。
我们创建了一个虚拟函数,它什么也不做,看看我们的测试用例是否会被接受为参数。
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
)
如果没有第二个参数,那么我们的返回类型是什么?它可以是 any
-- 因为我们可以使用任何被忽略的第二个参数调用函数 -- 或者它只能是 undefined
吗?这是一个预期行为的问题,因此没有正确或错误的答案。
正如目前所写,单参数函数将传递 any
返回类型,因为第二个参数的值为 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
)
但是,我们可以更改函数的签名以强制只能返回 void
/undefined
。
// FAIL when returning a value with second argument explicitly disallowed
checkFunc (
async (a: string, b?: never) => a
)
我们还可以通过显式设置 checkFunc
的泛型而不是允许推断它们来强制失败。
// FAIL based on generics <string, never> -- must have <string, string> to pass
checkFunc<string, never> (
async (a: string) => a
)