这是一个有趣的挑战,但我找到了一个足够好的解决方案,并且似乎可行。
我的想法是采用你最初的联合类型Input
并将所有内容都变成泛型,因为缩小了受歧视的联合(基于您的name
)实际上只适用于文字。
首先,让我们创建一个具有所有可能的类型name
values:
type Names = Input["name"];
接下来,创建一个“查找”泛型类型,给定name
作为类型参数,给你content
类型。例如,ContentByName<"method_a">
is ContentA
.
type ContentByName<TName extends Names> = {
[i in Input as i["name"]]: i["content"];
}[TName];
这样,我们为您创建了一个特定的类型my_methods
目的。这似乎让编译器足够清楚地知道名称和类型类型确实属于彼此:
type Methods = { [name in Names]: (content: ContentByName<name>) => void };
const my_methods: Methods = { // <-- added to your code here
// ...
}
最后你的foo
函数也需要是通用的,为此我们还需要创建一个通用版本Input
type.
type InputByName<TName extends Names> = {
name: TName;
content: ContentByName<TName>;
};
function foo<TName extends Names>(input: InputByName<TName>) { // <-- added
//...
}
请注意,您可以愉快地使用普通的 ol' 调用此函数Input
就像你以前做的那样。这是完全有效的:
function foo_old(input: Input) {
return foo(input);
}
我们实际上并没有change有关类型的任何信息;我们只是帮助编译器推理它们。
这是游乐场链接与我的更改 https://www.typescriptlang.org/play?#code/C4TwDgpgBAwg9gO2BJBBKBeKBnYAnASwQHMBuAKHNElkWSQCFMoEBXAWwCMI8KrxoASQRhWwdFgDe5KCwCG7CAC4oAIkXAAFnAAmAfTmqKsgMZ0UwFfCQXUFAL59qQkWKZSZ8xSvUQtuvU4jTzMbJCtzRgcnAShhUWBmeLF0AB8412AGGJoAOQUIbCTMgG1VBALVAF0c6Gt6LJB8xQAeABVm6AgAD3odIs7sAD5maVkSgigiDISoOSKCMorFaqqVRdVQhuqHEo6CmspnKABZP21+0agS5ehpwbWoAAotiwiwxs6W26GASkwRgA3OAEHRQRyUUK4KDsEB6DQXbAqM7+S4eWQIgJyFQvSKWWgfVD-DAjMayKAAegpUAAdHTPPYADSeTH6Tg417hAkNBjE0meWRU2n02RM8gQ-g0ZKfArtTpQHp9AYFYajTy3FT7RTGKCc-H1CwMJqyrUQIbRSgAM1YCBMwAIiCglrgcDlBQVvRQl0GQyeRASKmlRq+pr+UDJeD8rDwCBhcNZ2AmmRptyqfuTet+DitNrtDtjzrgejgABsdOmAzMxP8ybJI8BowWXRXqw4gA.