【问题标题】:How mapped types works with base types?映射类型如何与基本类型一起使用?
【发布时间】:2020-07-13 18:07:44
【问题描述】:

我不明白为什么在下面的情况下 type T0 是一个字符串而不是一个带有键 "toString" 、 "slice" "split" 的对象......以及为什么 type T1 是一个带有键类型的对象string 虽然我们知道 keyof any 是 string | symbol | number?

type MappedType<T> = {
[K in keyof T]: T;
}

type T0 = MappedType<string>;
type T1 = MappedType<any>;

【问题讨论】:

    标签: typescript


    【解决方案1】:

    T0 的权威答案可以在实现“同态mapped types”或{[K in keyof T]: ...} 形式的映射类型的pull request 中找到,其中T 是泛型类型参数。 (注意,它最初被称为“同构”而不是“同构”,但它是同一回事。)

    这种映射类型的正常用例是T 是某个 objdct 类型;在这种情况下,映射会保留来自T 的键名以及它们的“read-onliness”和“optionality”修饰符。 (可以通过在映射类型中显式设置它们来覆盖这些修饰符。)

    那么当T 是像string 这样的原始类型时会发生什么?拉取请求说“我们只是产生那个原始类型”。事实证明这非常有用,尤其是在递归使用映射类型的情况下。像

    这样的类型
    type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
    

    将遍历嵌套的对象类型并使每个子属性成为可选的... 并保留原语

    declare const ab: DeepPartial<{ a: { b: string } }>;
    const str = ab.a!.b!; // string
    

    这几乎总是人们想要的。如果这样的类型继续向下递归到像lengthtoUpperCase 这样的包装原语的所有属性,你最终会得到一个基本上没用的类型。然后获得“正常”版本的唯一方法是使用conditional types 来终止下降而不是映射原语:

    type DeepPartial2<T> = 
      { [K in keyof T]?: T[K] extends object ? DeepPartial2<T[K]> : T[K] }
    

    这不太方便(在 TS2.8 引入条件类型之前是不可能的)。

    在某种意义上,人们通常希望为同态映射的事物保留“相同的一般形状”,但“相同的一般形状”的含义并不总是显而易见的。对象类型保持对象类型。基元保持基元。最初,数组被视为常规对象类型,产生了一种几乎无用的类型,它将数组方法转换为无法识别的东西。这对任何人来说都不愉快,这就是为什么TypeScript 3.1 changed it 映射数组类型仍然是数组类型,而映射元组类型仍然是元组类型。


    剩下的就是T1,其中any 的属性的同态映射会产生一个可索引的类型。

    之前链接的拉取请求没有进入,但实施者在commentGitHub issue 解释了他的推理,将此行为报告为错误:

    keyof anystring | number | symbol,因此应用于any 的映射类型会产生等价于{ [x: string]: XXX }

    注意他说的是“相当于”。 symbol 会自动从映射类型中删除,因此 {[K in "a" | symbol]: string} 会产生 {a: string}。您允许分别拥有stringnumber 索引,因此{[K in string | number]: string}{[k: string]: string; [k: number]: string}。但是由于数字键在TypeScriptJavaScript 中被视为字符串值,因此这与{[k: string]: string} 相同。 (如果您想了解更多关于 stringnumbersymbol 键映射后会发生什么,您可以查看 this documentation。)

    就我个人而言,我不是 100% 同意 keyof any 被映射到一个 string 索引而不是 stringnumber,因为 {[K in keyof T]: K} 会显示出不同...但它是一个小问题。

    重要的一点来自评论的其余部分:

    您可能会争辩说,当同态映射类型应用于any 时,我们应该只产生any,但这会不太精确。例如 { [K in keyof T]: number }T 实例化为 any 真的应该产生 { [x: string]: number } 而不仅仅是 any

    所以你去; any 被视为具有字符串可索引键的对象类型,因此对其进行映射会产生合理的结果。该评论是我所见过的最接近该问题的规范答案的评论。


    好的,希望对您有所帮助;祝你好运!

    Playground link to code

    【讨论】:

      猜你喜欢
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-22
      • 1970-01-01
      • 2011-12-01
      • 2012-10-19
      相关资源
      最近更新 更多