难以理解类型索引
Trouble understanding type indexing
我无法理解以下类型定义:
type MergeHandlersReturnType<H extends Record<string, any>> = {
[K in keyof H]: ReturnType<H[K]>
}[keyof H]
使用相似类型分解上述定义我不明白为什么以下会给我编译器错误
interface R1 extends Record<string, any> {
"key1": () => 0|1
}
const v1: R1 = {
"key1": () => 1,
"key2": () => 2,
"key3": () => 3
}
type Merged<R1> = {
[K in keyof R1]: ReturnType<R1[K]>
^^^^^
}[keyof R1]
Type 'R1[K]' does not satisfy the constraint '(...args: any) => any'.
Type 'R1[keyof R1]' is not assignable to type '(...args: any) => any'.
Type 'R1[string] | R1[number] | R1[symbol]' is not assignable to type '(...args: any) => any'.
Type 'R1[string]' is not assignable to type '(...args: any) => any'.ts(2344)
我原以为 Merged
类型是 R1
键的 return 类型的并集,但索引失败了。
通用参数 R1
必须扩展 Record<string, any>
才能正常工作,或者假设它是任何参数。
或者更准确地说,它需要扩展一个支持indexed signatures的类型。
如果将 Merged<>
的定义与原始定义进行比较,您应该能够看到您缺少约束。
interface R1 extends Record<string, any> {
"key1": () => 0|1
}
const v1: R1 = {
"key1": () => 1,
"key2": () => 2,
"key3": () => 3
}
interface MyType {
[k: string]: any
}
type MergedForMyType<R1 extends MyType> = {
[K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]
type MergedForRecordGeneric<R1 extends MyType | Record<string, any>> = {
[K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]
您看到编译器错误的原因有几个:
Merged<R1>
表示 R1
是泛型类型变量的名称,而不是 R1
接口,因此 R1
在 Merged
非常类似于泛型 T
,它没有类型定义,并且假设没有可以通过 T[K]
.
访问的属性
将Merged<R1>
改成Merged
后,因为Record
在interface R1 extends Record<string, any> {
中有一个类型any
,结果Merged
union type will always be any
... ReturnType
in [K in keyof R1]: ReturnType<R1[K]>
看Record
的第二个参数是什么,因为它比较宽泛,不分析R1
界面中的属性。要解决此问题,我建议您添加特定类型而不是像这样的 any
:interface R1 extends Record<string,() => 0|1|2|3> {
。当然,另一种方法是摆脱扩展并用你的类型定义你的键,这样你就不必手动定义联合类型并使用 Merged
就像你想要的那样:
interface R1 {
"key1": () => 0|1
"key2": () => 2,
"key3": () => 3
}
这实际上取决于您的用例,希望上面解释了为什么您会在问题中看到错误。
这里是link到playground。
我无法理解以下类型定义:
type MergeHandlersReturnType<H extends Record<string, any>> = {
[K in keyof H]: ReturnType<H[K]>
}[keyof H]
使用相似类型分解上述定义我不明白为什么以下会给我编译器错误
interface R1 extends Record<string, any> {
"key1": () => 0|1
}
const v1: R1 = {
"key1": () => 1,
"key2": () => 2,
"key3": () => 3
}
type Merged<R1> = {
[K in keyof R1]: ReturnType<R1[K]>
^^^^^
}[keyof R1]
Type 'R1[K]' does not satisfy the constraint '(...args: any) => any'.
Type 'R1[keyof R1]' is not assignable to type '(...args: any) => any'.
Type 'R1[string] | R1[number] | R1[symbol]' is not assignable to type '(...args: any) => any'.
Type 'R1[string]' is not assignable to type '(...args: any) => any'.ts(2344)
我原以为 Merged
类型是 R1
键的 return 类型的并集,但索引失败了。
通用参数 R1
必须扩展 Record<string, any>
才能正常工作,或者假设它是任何参数。
或者更准确地说,它需要扩展一个支持indexed signatures的类型。
如果将 Merged<>
的定义与原始定义进行比较,您应该能够看到您缺少约束。
interface R1 extends Record<string, any> {
"key1": () => 0|1
}
const v1: R1 = {
"key1": () => 1,
"key2": () => 2,
"key3": () => 3
}
interface MyType {
[k: string]: any
}
type MergedForMyType<R1 extends MyType> = {
[K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]
type MergedForRecordGeneric<R1 extends MyType | Record<string, any>> = {
[K in keyof R1]: ReturnType<R1[K]>
} [keyof R1]
您看到编译器错误的原因有几个:
访问的属性Merged<R1>
表示R1
是泛型类型变量的名称,而不是R1
接口,因此R1
在Merged
非常类似于泛型T
,它没有类型定义,并且假设没有可以通过T[K]
.将
Merged<R1>
改成Merged
后,因为Record
在interface R1 extends Record<string, any> {
中有一个类型any
,结果Merged
union type will always beany
...ReturnType
in[K in keyof R1]: ReturnType<R1[K]>
看Record
的第二个参数是什么,因为它比较宽泛,不分析R1
界面中的属性。要解决此问题,我建议您添加特定类型而不是像这样的any
:interface R1 extends Record<string,() => 0|1|2|3> {
。当然,另一种方法是摆脱扩展并用你的类型定义你的键,这样你就不必手动定义联合类型并使用Merged
就像你想要的那样:
interface R1 {
"key1": () => 0|1
"key2": () => 2,
"key3": () => 3
}
这实际上取决于您的用例,希望上面解释了为什么您会在问题中看到错误。
这里是link到playground。