问题描述
这有效:
class Dog {
speak() {
return "woof" as const;
}
}
type ExtractSpeak<T extends [...Dog[]]> = { [P in keyof T]: T[P] extends Dog ? ReturnType<T[P]["speak"]> : never };
// Type of Example is ["woof","woof"]
type Example = ExtractSpeak<[Dog,Dog]>;
但是,如果没有条件类型,为什么它不起作用?
// Error: Type '"speak"' cannot be used to index type 'T[P]'. (2536)
type ExtractSpeak<T extends [...Dog[]]> = { [P in keyof T]: ReturnType<T[P]["speak"]> };
除了具有T[P]
方法的类型返回speak
的类型之外,"woof"
何时会引用?
解决方法
这是TypeScript中的错误;参见microsoft/TypeScript#27995。当您创建mapped type over a tuple/array时,出现的类型也将是元组/数组;也就是说,您实际上只是在映射数组的数字索引。但是在映射类型的定义中,编译器没有注意这一点。相反,它认为K in keyof T
(其中T
是数组类型)可能在每个可能的键上迭代K
,如下所示:
type DogArrayKeys = keyof [Dog,Dog];
// number | "0" | "1" | "length" | "toString" | "toLocaleString" | "pop" |
// "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" |
// "splice" | "unshift" | "indexOf" | "lastIndexOf" |
// ... 14 more ... | "includes"
例如,由于[Dog,Dog]["length"]
的类型为2
而不是Dog
,因此编译器不允许您将T[K]
视为Dog
。 Blecch。
无论如何,这是一个错误,如果已修复,那就太好了。我想您可以转到ms / TS#27995,然后给它一个?。但实际上,它在任何优先级列表上可能都不高(目前在待办事项列表中)。标准的解决方法是只使用Extract<T[K],Dog>
之类的条件类型并继续进行,这基本上就是上面的内容。