如何通过条件类型检查区分不同的函数签名?

How to distinguish different functions signature with conditional type checks?

提问人:awdk 提问时间:11/1/2022 最后编辑:awdk 更新时间:11/2/2022 访问量:150

问:

我想在条件类型检查中区分以下函数类型:

type SyncFn = () => void;
type AsyncFn = (data: number) => Promise<void>;
type SyncFnWithArg = (data: number) => void;

因此,我可以使用 @Titian Cernicova-Dragomir 发布的 KeyOfType,并在给定接口中获取与给定类型匹配的密钥。

我尝试了以下方法:

type SyncFn = () => void;
type AsyncFn = (data: number) => Promise<void>;
type SyncFnWithArg = (data: number) => void;

interface Foo {
    a?: string;
    b?: number;
    c: number;
    d: string;
    f1?: SyncFn;
    f2?: AsyncFn;
    f3?: SyncFnWithArg;
}

// note: `KeyOfType` from https://stackoverflow.com/questions/49752151/typescript-keyof-returning-specific-type
type KeyOfType<T, V> = keyof { [P in keyof T as T[P] extends V? P: never]: any }

type KeyOfTypeOptionalIncluded<T, Condition> = KeyOfType<T, Condition | undefined>


let onlyStrings: KeyOfTypeOptionalIncluded<Foo, string>;
onlyStrings = 'a' // ✅ working as expected 🎉
onlyStrings = 'b' // ✅ erroring out as expected 🎉
onlyStrings = 'd' // ✅ working as expected 🎉


let onlySyncFn: KeyOfTypeOptionalIncluded<Foo, SyncFn>;
onlySyncFn = 'f1' // ✅ working as expected 🎉
onlySyncFn = 'f2' // ✅ erroring out as expected 🎉
onlySyncFn = 'f3' // ✅ erroring out as expected 🎉

let onlyAsyncFn: KeyOfTypeOptionalIncluded<Foo, AsyncFn>;
onlyAsyncFn = 'f1' // ✅ erroring out as expected 🎉
onlyAsyncFn = 'f2' // ✅ working as expected 🎉
onlyAsyncFn = 'f3' // ✅ erroring out as expected 🎉

let onlySyncFnWithArg: KeyOfTypeOptionalIncluded<Foo, SyncFnWithArg>;
onlySyncFnWithArg = 'f1' // 😭 should error out 😭
onlySyncFnWithArg = 'f2' // 😭 should error out 😭
onlySyncFnWithArg = 'f3' // ✅ working as expected 🎉

TS游乐场

问题是它被输入为,而它应该是......onlySyncFnWithArg"f1" | "f2" | "f3""f3"

enter image description here


我还注意到,如果我修改并删除它的参数,那么我会遇到更多问题,因为 的类型定义现在是不正确的,因为现在它不仅仅是在上面的第一个 TS Playground 中。AsyncFnonlySyncFn"f1" | "f2""f1"

第二个 TS 游乐场

我想这与打字稿中的函数重载是如何完成的有关,但我真的不知道,所以这就是我寻求帮助的原因......也许它不相关,但是我们能够在 TS 中进行这样的函数类型区分吗?

typescript 条件类型 keyof 函数签名

评论


答:

1赞 Robby Cornelissen 11/1/2022 #1

可以通过更改类型来解决此问题,如下所示:KeyOfType

  1. 检查类型关系的两个方向 ( 和 ):A extends BB extends A
  2. 将条件类型子句中使用的类型包装在元组 () 中。[A] extends [B]
type KeyOfType<T, V> = keyof {
  [P in keyof T as [T[P]] extends [V]
    ? [V] extends [T[P]]
      ? P
      : never
    : never
  ]: any
}

在这里找到一个 playground 示例,并在这里找到一个有趣的讨论,讨论测试类型相等的各种方法(每种方法都有自己的注意事项)。

评论

0赞 awdk 11/2/2022
哦。。。这是有道理的!!这对我来说是全新的(检查两个方向)!非常感谢!🎉