如何编写类型安全的Amplify-JS v6 GraphQL订阅回调函数签名?
我正在使用v6.0.9版本的aws-amplify库(非5.x.x版本),需要封装client.graphql({ query: typedGqlString, variables}).subscribe({ next, error })调用,以此统一处理所有GraphQL订阅的取消订阅、错误处理,以及断网重连时的数据刷新逻辑。
该v6版本的Amplify库支持如下的类型化GraphQL字符串写法:
import { generateClient} from "aws-amplify/api"; const client = generateClient(); type GeneratedSubscription<InputType, OutputType> = string & { __generatedSubscriptionInput: InputType; __generatedSubscriptionOutput: OutputType; }; interface SubscriptionOnCreateClubDeviceArgs { clubId: string; } interface SubscriptionOnCreateClubDeviceCallbackPayload { onCreateClubDevice: ClubDevice; /* ClubDevice 类型在其他地方定义 */ } const subscriptionOnCreateClubDevice = /* GraphQL */ ` subscription OnCreateClubDevice($clubId: String!) { onCreateClubDevice(clubId: $clubId) { (... clubDevice 的GQL类型字段名) } } ` as GeneratedSubscription< SubscriptionOnCreateClubDeviceArgs, SubscriptionOnCreateClubDeviceCallbackPayload > client.graphql({ query: subscriptionOnCreateClubDevice, variables: { clubId: "foo" } }).subscribe({ next: (payload/* 不需要显式声明为 SubscriptionOnCreateClubDeviceCallbackPayload */) => { // payload 在编译时就被识别为 SubscriptionOnCreateClubDeviceCallbackPayload 类型 ... } });
这个类型化特性非常实用:Amplify会自动对variables字段的合法性做类型检查,同时确保next函数只能引用其参数上实际存在的字段。
我的目标是编写一个封装函数,接收query、variables和next作为参数,但Amplify-JS库的内部类型并未对外导出。
我遇到的核心问题是:subscribe方法的参数是两种类型的联合:Partial<Observer<NeverEmpty<OUTPUT_TYPE>>> | ((value: NeverEmpty<OUTPUT_TYPE>) => void)
我只会传入包含next字段的Partial<Observer<NeverEmpty<OUTPUT_TYPE>>>类型(因为单独的函数类型已经被废弃),但由于Observer和NeverEmpty是未对外暴露的复杂内部类型,我无法正确编写封装函数的类型签名。
我尝试过使用Exclude<T, U>工具类型,但无法明确指定要排除的函数类型;也尝试过infer关键字进行类型推断,但推断出的类型丢失了Partial<Observer<NeverEmpty<OUTPUT_TYPE>>>中next字段的静态类型信息。
请问有没有其他方法可以在编译时静态移除那个废弃的函数类型,从而提取出Partial<Observer<NeverEmpty<OUTPUT_TYPE>>>中订阅通知回调的类型?或者有没有更优的类型安全封装方案?
内容的提问来源于stack exchange,提问作者Tim Heilman

