简体   繁体   English

如何从 typescript 中的数组值创建 object 键

[英]How to create object keys from array values in typescript

How to type following function in typescript so I get autocompletion & error prevention.如何在 typescript 中键入以下 function 以便我获得自动完成和错误预防。

Using Typescript 4.7.4使用 Typescript 4.7.4

// reference fn
function doSomething(list) {

    const data = {};

    list.map(item => {
        data[item] = 'value type string|number|bool|null'   
    });

    return data;
}

// calling it like
const data = doSomething([
    'phone_number',
    'customer_email'
]);

// get IDE autocomplete here (for only properties inside data)
console.log(data.phone_number);
console.log(data.customer_email);

// typescript yell when try to access invalid properties
console.log(data.phone_numbersss);

You can do it provided the array being used is effectively a compile-time constant at the point of the function call (so TypeScript knows what its values are).您可以这样做,前提是所使用的数组在 function 调用点是有效的编译时常量(因此 TypeScript 知道它的值是什么)。 Otherwise, TypeScript doesn't know what the array contents are and will have to assume any string.否则,TypeScript 不知道数组内容是什么,并且必须假设任何字符串。 There are at least two ways that constraint can be satisfied:至少有两种方式可以满足约束:

  1. You can say an array is constant directly by applying a constant assertion to it:您可以通过对其应用常量断言来直接说数组是常量:

     const names = ["phone_number", "customer_email"] as const; // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^
  2. You can use an array literal at the point of the call, and use a variadic tuple type for the parameter's type (more below).您可以在调用时使用数组文字,并为参数类型使用可变元组类型(更多内容见下文)。

Once we know that the array's contents are a compile-time constant to TypeScript, we can use a mapped type to map an array that extends string[] to an object with the array elements as keys and the desired property types:一旦我们知道数组的内容是 TypeScript 的编译时常量,我们就可以使用映射类型到 map 一个数组,该数组将string[]扩展为 object 数组元素和所需的属性作为键

type DoSomethingResult<T extends readonly string[]> = {
    [Key in T[number]]: string | number | boolean | null;
};

Implementing the function requires creating the object (rather than an array) and giving the properties some value;实现 function 需要创建 object(而不是数组)并赋予属性一些值; I've chosen null :我选择null

function doSomething<T extends readonly string[]>(list: [...T]): DoSomethingResult<T> {
    // Variadic tuple type −−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^
    return Object.fromEntries(list.map((key) => [key, null])) as DoSomethingResult<T>;
}

Here's the call:这是电话:

const data = doSomething([
    "phone_number",
    "customer_email"
]);

Then all of your given test cases work.然后所有给定的测试用例都可以工作。

Playground link 游乐场链接

Note that the array has to be an array literal;请注意,数组必须是数组字面量; this won't work:这不起作用:

// WON'T WORK AS DESIRED
const names = [
    "phone_number",
    "customer_email"
];
const data = doSomething(names);

TypeScript infers the type of the array to be string[] , not ["phone_number", "customer_email"] . TypeScript 推断数组的类型是string[] ,而不是["phone_number", "customer_email"] (It would work if you added an as const on the array.) (如果您在数组上添加了as const ,它会起作用。)


If you had to support versions of TypeScript that didn't have variadic tuple types (introduced in v4.0), you'd use the as const version instead:如果您必须支持没有可变元组类型(在 v4.0 中引入)的 TypeScript 版本,则可以改用as const版本:

function doSomething<T extends readonly string[]>(list: T): DoSomethingResult<T> {
    // Using `T` directly as the type −−−−−−−−−−−−−−−−−−^
    return Object.fromEntries(list.map((key) => [key, null])) as DoSomethingResult<T>;
}
// ...
const data = doSomething([
    "phone_number",
    "customer_email"
] as const);
//^^^^^^^^

Playground link using v3.9.7 使用 v3.9.7 的游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM