在元组上使用映射类型时,为什么需要条件类型?

问题描述

这有效:

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>之类的条件类型并继续进行,这基本上就是上面的内容。

Playground link to code

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...