如何将函数的输入参数与其 return 类型相关联以利用自动建议功能
How to associate a function's input arguments with its return type to leverage autosuggest features
我正在尝试使用泛型 link 函数的参数类型和 return 类型。我已经找到了一个解决方案,但我发现它不是最优的,因为我觉得它可以做得更好。
基本上,我有以下功能:
function postCommand<T extends AvailableCommands>(
commandName: T,
commandArguments: ArgumentType<T>
): Observable<PayloadType<T>> {
return httpClient.post<PayloadType<T>>(`/command/${commandName}`, commandArguments);
}
结合以下(示例)定义:
type AvailableCommands =
| 'create-group'
| 'create-post';
type ArgumentType<T extends AvailableCommands> = T extends 'create-group'
? CreateGroupArguments
: T extends 'create-post'
? CreatePostArguments
: never;
type PayloadType<T extends AvailableCommands> = T extends 'create-group'
? CreateGroupPayload
: T extends 'create-post'
? CreatePostPayload
: never;
注意:*Arguments
和 *Payload
是在对象的普通接口范围之外定义的。例如,对于 CreatePostArguments
,键 groupId
和 body
。
httpClient
也在范围之外定义(它基本上是 Angular7 HTTP 客户端)
上面的代码允许我将函数 postCommand
与输入变量 commandName
的自动建议和基于我输入的 commandName
的 commandArguments
的自动建议一起使用。当我订阅 returned observable.
时,也会推断出 commandPayload
现在,使用条件类型很丑陋,而且不容易被其他开发人员理解。
这让我试图找到另一种方式,在那里我偶然发现了 [
这将代码更改如下:
function postCommand<T extends AvailableCommands>(
commandName: T,
commandArguments: CommandMap[T]['arguments']
): Observable<CommandMap[T]['payload']> {
return httpClient.post<CommandMap[T]['payload']>(`/command/${commandName}`, commandArguments);
}
interface CommandMap {
'create-group': { arguments: CreateGroupArguments; payload: CreateGroupPayload };
'create-post': { arguments: CreatePostArguments; payload: CreatePostPayload };
}
现在,这看起来更具可读性并且具有相同的效果。我仍然有自我暗示。唯一需要注意的是:如果我从 CommandMap
接口中省略 create-post
,编译器不会介意。这是上面两个实现的问题。
这主要是我想要的,除了我提到的警告。所以,我现在的问题是:
有没有办法让编译器注意到我没有为 CommandMap
中的所有 AvailableCommands
定义映射,并且仍然对参数和 return 进行自动建议postCommand
?
的类型
(我用我的最新版本创建了一个 Playground,以及 post
的模拟实现和我在我的项目中使用的 TypeScript 版本)
编辑:
对我来说最好的整体答案隐藏在众目睽睽之下:
我现在基本上只用一种
export interface CommandMap {
[index: string]: { arguments: any; payload: any };
'create-group': { arguments: CreateGroupArguments; payload: CreateGroupPayload };
'create-post': { arguments: CreatePostArguments; payload: CreatePostPayload };
}
和函数调用:
public postCommand<T extends keyof CommandMap>(
commandName: T,
commandArguments: CommandMap[T]['arguments']
): Observable<CommandMap[T]['payload']> {
return this.httpClient.post<CommandMap[T]['payload']>(`/command/${commandName}`, commandArguments);
}
泛型现在扩展 keyof CommandMap
。因为 CommandMap
已经有了我的命令的所有定义,所以我不需要额外的 AvailableCommands
类型。
所有 AutoSuggestion 功能仍然可用,错误出现在正确的位置(接口定义本身,如果有的话)
如果 CommandMap
的键与 AvailableCommands
的键不匹配,如果您正在寻找编译器错误,您可以在单独的行中实现:
type VerifyCommandMap<
// if the next line is an error, CommandMap has extra keys
K extends AvailableCommands = keyof CommandMap,
// if the next line is an error, CommandMap is missing some keys
L extends keyof CommandMap = AvailableCommands
> = true;
基本上,您是在强制默认参数满足一般约束,只有当 AvailableCommands
与 keyof CommandMap
相同时它们才会满足这些约束。
有帮助吗?
我正在尝试使用泛型 link 函数的参数类型和 return 类型。我已经找到了一个解决方案,但我发现它不是最优的,因为我觉得它可以做得更好。
基本上,我有以下功能:
function postCommand<T extends AvailableCommands>(
commandName: T,
commandArguments: ArgumentType<T>
): Observable<PayloadType<T>> {
return httpClient.post<PayloadType<T>>(`/command/${commandName}`, commandArguments);
}
结合以下(示例)定义:
type AvailableCommands =
| 'create-group'
| 'create-post';
type ArgumentType<T extends AvailableCommands> = T extends 'create-group'
? CreateGroupArguments
: T extends 'create-post'
? CreatePostArguments
: never;
type PayloadType<T extends AvailableCommands> = T extends 'create-group'
? CreateGroupPayload
: T extends 'create-post'
? CreatePostPayload
: never;
注意:*Arguments
和 *Payload
是在对象的普通接口范围之外定义的。例如,对于 CreatePostArguments
,键 groupId
和 body
。
httpClient
也在范围之外定义(它基本上是 Angular7 HTTP 客户端)
上面的代码允许我将函数 postCommand
与输入变量 commandName
的自动建议和基于我输入的 commandName
的 commandArguments
的自动建议一起使用。当我订阅 returned observable.
commandPayload
现在,使用条件类型很丑陋,而且不容易被其他开发人员理解。
这让我试图找到另一种方式,在那里我偶然发现了 [
这将代码更改如下:
function postCommand<T extends AvailableCommands>(
commandName: T,
commandArguments: CommandMap[T]['arguments']
): Observable<CommandMap[T]['payload']> {
return httpClient.post<CommandMap[T]['payload']>(`/command/${commandName}`, commandArguments);
}
interface CommandMap {
'create-group': { arguments: CreateGroupArguments; payload: CreateGroupPayload };
'create-post': { arguments: CreatePostArguments; payload: CreatePostPayload };
}
现在,这看起来更具可读性并且具有相同的效果。我仍然有自我暗示。唯一需要注意的是:如果我从 CommandMap
接口中省略 create-post
,编译器不会介意。这是上面两个实现的问题。
这主要是我想要的,除了我提到的警告。所以,我现在的问题是:
有没有办法让编译器注意到我没有为 CommandMap
中的所有 AvailableCommands
定义映射,并且仍然对参数和 return 进行自动建议postCommand
?
(我用我的最新版本创建了一个 Playground,以及 post
的模拟实现和我在我的项目中使用的 TypeScript 版本)
编辑:
对我来说最好的整体答案隐藏在众目睽睽之下:
我现在基本上只用一种
export interface CommandMap {
[index: string]: { arguments: any; payload: any };
'create-group': { arguments: CreateGroupArguments; payload: CreateGroupPayload };
'create-post': { arguments: CreatePostArguments; payload: CreatePostPayload };
}
和函数调用:
public postCommand<T extends keyof CommandMap>(
commandName: T,
commandArguments: CommandMap[T]['arguments']
): Observable<CommandMap[T]['payload']> {
return this.httpClient.post<CommandMap[T]['payload']>(`/command/${commandName}`, commandArguments);
}
泛型现在扩展 keyof CommandMap
。因为 CommandMap
已经有了我的命令的所有定义,所以我不需要额外的 AvailableCommands
类型。
所有 AutoSuggestion 功能仍然可用,错误出现在正确的位置(接口定义本身,如果有的话)
如果 CommandMap
的键与 AvailableCommands
的键不匹配,如果您正在寻找编译器错误,您可以在单独的行中实现:
type VerifyCommandMap<
// if the next line is an error, CommandMap has extra keys
K extends AvailableCommands = keyof CommandMap,
// if the next line is an error, CommandMap is missing some keys
L extends keyof CommandMap = AvailableCommands
> = true;
基本上,您是在强制默认参数满足一般约束,只有当 AvailableCommands
与 keyof CommandMap
相同时它们才会满足这些约束。
有帮助吗?