代码之家  ›  专栏  ›  技术社区  ›  A. L

如何将只读字符串[]泛型转换为已知对象

  •  1
  • A. L  · 技术社区  · 3 年前

    我正在尝试转换一个泛型 readonly string[] 转换为具有已知关键点的对象。但我遇到了一个错误:

    Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record<T[number], number>'.
      No index signature with a parameter of type 'string' was found on type 'Record<T[number], number>'.
    

    代码:

    class ArrayToObject<T extends readonly string[]> {
      constructor (private keys : T) {}
    
      GET_OBJECT () {
        const all = {} as Record<T[number], number>
        for (const index in this.keys) {
          all[this.keys[index]] = index
        }
        return all;
      }
    }
    

    我基本上想从泛型中得到的东西与此类似:

    const a = ["a", "b"] as const
    const o : Record<typeof a[number], number> = {
      a : 1,
      b : 2
    }
    

    playground

    1 回复  |  直到 3 年前
        1
  •  2
  •   Cheng Dicky    3 年前

    这是因为类型系统只能知道 T extends readonly string[] 但是它不能正确地推断其元素的类型。将T定义为元素类型可以帮助类型系统推断它。

    此外 for...in 语句将产生一个字符串键值。您需要将其转换为数字或使用 Array.keys() Array.entries() 以获取数字索引。

    class ArrayToObject<T extends string> {
      constructor (private keys : readonly T[]) {}
      GET_OBJECT () {
        const all = {} as Record<T, number>
        for (const [index, value] of this.keys.entries()) {
          all[value] = index // + 1 if you want 1-based
        }
        return all;
      }
    }
    

    playground

        2
  •  0
  •   Mark Hanna    3 年前

    您可以使用从只读字符串中获取字符串并集 type inference ,如下所示:

    const a = ["a", "b"] as const;
    
    type StringFromReadonlyArray<T extends readonly string[]> = T extends readonly (infer U)[] ? U : string;
    
    const tooMany: Record<StringFromReadonlyArray<typeof a>, number> = {
      a: 1,
      b: 2,
      c: 3, // <-- Error: Type '{ a: number; b: number; c: number; }' is not assignable to type 'Record<"a" | "b", number>'.
    };
    
    const notEnough: Record<StringFromReadonlyArray<typeof a>, number> = { // <-- Error: Property 'b' is missing in type '{ a: number; }' but required in type 'Record<"a" | "b", number>'.
      a: 1,
    };
    
    const justRight: Record<StringFromReadonlyArray<typeof a>, number> = {
      a: 1,
      b: 2,
    };
    

    TypeScript Playground

    那个 StringFromReadonlyArray 如果可能的话,实用程序类型会从只读数组中提取字符串并集,否则它将解析为泛型 string 类型