[英]Type that depends on generic argument as value argument to function
I have a generic type Group
that looks like this:我有一个看起来像这样的通用类型
Group
:
// K -> Key
// I -> Input
type Group<K, I> = {
key: K;
func: (i: I) => void;
};
There is a fixed number of Group
values which I declared in an object like this:我在 object 中声明了固定数量的
Group
值,如下所示:
const GROUPS = {
"a": {
func: (i: {x: number}) => { console.log(i); },
key: "a",
},
"b": {
func: (i: { y: number }) => { console.log(i) },
key: "b"
}
} as const;
I then have 2 utility types to refer to all the possible group keys and all the possible group inputs:然后,我有 2 种实用程序类型来引用所有可能的组键和所有可能的组输入:
type GroupKey = keyof typeof GROUPS;
type GroupInput<K extends GroupKey> = Parameters<typeof GROUPS[K]["func"]>[0];
// GroupValue test:
type TestType = GroupInput<"b">; // { y: number}, this works
Finally, I have a function that receives both a group key and a group input:最后,我有一个 function 接收组键和组输入:
function test<K extends GroupKey>(key: K, input: GroupInput<K>) {
if (key === "b") {
(input.y); // Why doesn't TypeScript understand that `input.y` must be `number` here?
}
}
This function is generic over the type of the key that is passed in and unfortunately, TypeScript cannot "understand" that if key
is "b"
, then input
is of type { y: number }
.这个 function 对于传入的键的类型是通用的,不幸的是,TypeScript 无法“理解”如果
key
是"b"
,那么input
的类型是{ y: number }
。 Why is this the case, what is TypeScript missing to be able to do this?为什么会出现这种情况,TypeScript 缺少什么才能做到这一点? I'd especially like to find a GitHub issue on this (so that I can subscribe to it), but I wasn't able to find one as this type of thing is particularly hard to search for.
我特别想在这个问题上找到一个 GitHub 问题(以便我可以订阅它),但我无法找到一个,因为这种类型的东西特别难以搜索。
Please consider this snippet:请考虑这个片段:
const key = 'a' as GroupKey
const input = { y: 1 } // optionally cast as GroupInput<'b'> or as GroupInput<GroupKey>
test(key, input) // compiles, but not intended
The input
might be independent from the key
. input
可能独立于key
。 There are no guarantees input.y
must be a number when test
is called with value 'b'
as the first argument.不能保证
input.y
必须是一个数字,当test
被调用时,值'b'
作为第一个参数。 type TestType = GroupInput<"b">
uses literal type ( 'b'
) which allows Typescript to restrict 'a' | 'b'
type TestType = GroupInput<"b">
使用文字类型( 'b'
),它允许 Typescript 限制'a' | 'b'
'a' | 'b'
to just 'b'
. 'a' | 'b'
到'b'
。 The same applies for test('b', ...)
, but passing key of type 'a' | 'b'
这同样适用于
test('b', ...)
,但传递类型为'a' | 'b'
'a' | 'b'
allows to pass input of type GroupInput<'a' | 'b'>
'a' | 'b'
允许传递GroupInput<'a' | 'b'>
类型的输入GroupInput<'a' | 'b'>
. GroupInput<'a' | 'b'>
。
One option would be to check if 'y' in input
, but this still does not address the main issue of not allowing wrong arguments to test
.一种选择是检查
'y' in input
,但这仍然不能解决不允许错误的 arguments 进行test
的主要问题。 In general case input as GroupInput<'b'>
is unsafe and should be avoided at any cost.通常情况下
input as GroupInput<'b'>
是不安全的,应不惜一切代价避免。
A possible fix:一个可能的修复:
type Params = { [K in GroupKey]: [key: K, input: GroupInput<K>] } // key: and input: are used for auto-completion instead of generic arg_0, arg_1
function test2(...args: Params[GroupKey]) {
// const [key, input] = args // will not work
if (args[0] === "b") {
const input = args[1];
input.y; // number
}
}
test2('b', { y: 1 }) // ok
test2('b', { x: 1 }) // error
test2(key, input) // error
Because the input
parameter is independent from your key
parameter.因为
input
参数独立于您的key
参数。 input
is not required to have y
as a property although your key might be equal to 'b'
.尽管您的键可能等于
'b'
,但input
不需要将y
作为属性。 You would have to Typecast your input
:您必须对您的
input
进行类型转换:
function test<K extends GroupKey>(key: K, input: GroupInput<K>) {
if (key === "b") {
const typedInput = input as GroupInput<'b'>;
(typedInput.y)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.