gpt4 book ai didi

typescript :映射类型中的索引签名

转载 作者:行者123 更新时间:2023-12-03 17:20:01 33 4
gpt4 key购买 nike

怎样取型{ 'k': number, [s: string]: any }和抽象在'k'number ?我想要一个类型别名 T使得 T<'k', number>给出上述类型。

考虑以下示例:

function f(x: { 'k': number, [s: string]: any }) {}                           // ok
type T_no_params = { 'k': number, [s: string]: any }; // ok
type T_key_only<k extends string> = { [a in k]: number }; // ok
type T_value_only<V> = { 'k': V, [s: string]: any}; // ok
type T_key_and_index<k extends string, V> = { [a in k]: V, [s: string]: any };// ?
  • 使用 { 'k': number, [s: string]: any}直接作为函数参数的类型f作品。
  • 使用 [s: string]: any type 中的索引部分-别名作品
  • 使用 k extends stringtype -alias 也有效
  • 当结合 k extends string[s: string]: any在同一 type -别名,我得到一个解析错误(甚至不是语义错误,它甚至似乎不是有效的语法)。

  • 这在这里似乎有效:
    type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }
    但在这里,我不太明白为什么它不提示额外的属性( & 右侧的类型不应该允许具有额外属性的对象)。

    编辑 :
    回答中多次提到 &是交集算子,它的行为应该类似于集合论交集。然而,当涉及到额外属性的处理时,情况并非如此,如以下示例所示:
    function f(x: {a: number}){};
    function g(y: {b: number}){};
    function h(z: {a: number} & {b: number}){};

    f({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {a: number}
    g({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {b: number}
    h({a: 42, b: 58}); // compiles!
    在这个例子中,似乎 {a: 42, b: 58}都不是 {a: number} 类型,也不是 {b: number} 类型的,但它以某种方式结束在交叉点 {a: number} & {b: number} .这不是集合论交集的工作原理。
    这正是我自己 & 的原因-提案对我来说看起来很可疑。如果有人能详细说明如何将映射类型与 { [s: string]: any }“相交”,我将不胜感激。可以使类型“更大”而不是使其更小。

    我看过问题
  • Index signature for a mapped type in Typescript
  • How do I add an index signature for a mapped type

  • 但这些似乎没有直接关系,尽管名称相似。

    最佳答案

    type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }是定义您所追求的类型的正确方法。但要知道的一件事是( paraphrasing deprecated flag: keyofStringsOnly ):

    keyof type operator returns string | number instead of string when applied to a type with a string index signature.


    我不知道有什么方法可以将索引限制为 string类型而不是 string | number .实际允许 number访问 string index 似乎是一件合理的事情,因为它符合 Javascript 的工作方式(人们总是可以对数字进行字符串化)。另一方面,您不能安全地访问带有字符串值的数字索引。
    &类型运算符的工作方式类似于设置理论交集——它总是限制可能值的集合(或保持它们不变,但从不扩展)。在您的情况下,该类型将任何非字符串键作为索引排除在外。准确地说,您排除了 unique symbol作为索引。
    我认为您的困惑可能来自 Typescript 处理函数参数的方式。使用明确定义的参数调用函数与将参数作为变量传递的行为不同。在这两种情况下,Typescript 都确保所有参数都具有正确的结构/形状,但在后一种情况下,它另外不允许额外的 Prop 。

    Code illustrating the concepts:
    type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V };
    type WithNumber = HasKeyValue<"n", number>;
    const x: WithNumber = {
    n: 1
    };

    type T = keyof typeof x; // string | number
    x[0] = 2; // ok - number is a string-like index
    const s = Symbol("s");
    x[s] = "2"; // error: cannot access via symbol

    interface N {
    n: number;
    }

    function fn(p: N) {
    return p.n;
    }

    const p1 = {
    n: 1
    };

    const p2 = {
    n: 2,
    s: "2"
    };

    fn(p1); // ok - exact match
    fn(p2); // ok - structural matching: { n: number } present; additional props ignored
    fn({ n: 0, s: "s" }); // error: additional props not ignore when called explictily
    fn({}); // error: n is missing
    编辑
    对象字面量 - 显式创建某种形状的对象,如 const p: { a: number} = { a: 42 }被 Typescript 以一种特殊的方式处理。与常规结构推理相反,类型必须完全匹配。老实说这是有道理的,因为这些额外的属性 - 没有额外的可能不安全的 Actor - 无论如何都无法访问。

    [...] However, TypeScript takes the stance that there’s probably a bug in this code. Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error. [...] One final way to get around these checks, which might be a bit surprising, is to assign the object to another variable.


    TS Handbook
    解决此错误的另一个选择是...将其与 { [prop: string]: any } 相交.
    More code:
    function f(x: { a: number }) {}
    function g(y: { b: number }) {}
    function h(z: { a: number } & { b: number }) {}

    f({ a: 42, b: 58 } as { a: number }); // compiles - cast possible, but `b` inaccessible anyway
    g({ a: 42 } as { b: number }); // does not compile - incorrect cast; Conversion of type '{ a: number; }' to type '{ b: number; }' may be a mistake
    h({ a: 42, b: 58 }); // compiles!

    const p = {
    a: 42,
    b: 58
    };

    f(p); // compiles - regular structural typing
    g(p); // compiles - regular structural typing
    h(p); // compiles - regular structural typing

    const i: { a: number } = { a: 42, b: 58 }; // error: not exact match
    f(i); // compiles
    g(i); // error
    h(i); // error

    关于 typescript :映射类型中的索引签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64969300/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com