TypeScript是否可以从动态对象推断键? [英] Is it possible for TypeScript to infer keys from a dynamic object?

查看:137
本文介绍了TypeScript是否可以从动态对象推断键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要在这里实现的是从数组生成的对象的智能感知/自动完成-类似于Redux的Action Creator,可以将字符串数组(string[])简化为对象形状为{ [string]: string }.

What I'm trying to achieve here is intellisense/autocomplete for an object that's been generated from an array - something like an Action Creator for Redux, an array of strings (string[]) that can be reduced to an object with shape { [string]: string }.

例如:

const a = ['ONE', 'TWO', 'THREE'];

const b = a.reduce((acc, type) => ({ ...acc, [type]: type }), {});

console.log(b);
// Output: b = { ONE: 'ONE', TWO: 'TWO', THREE: 'THREE' };

我已经使用以下方法设法使TypeScript理解了很多. TypeScript知道键是字符串,但不知道它们是什么.

I've managed to get TypeScript to understand that much, using the below. TypeScript understands that the keys are strings, but does not know what they are.

interface ITypesReturnObject { [s: string]: string }

有没有人想出一种方法通知TypeScript对象上的键等于数组中的字符串?

Has anyone worked out a way to inform TypeScript that the keys on the object are equal to the strings in the array?

任何帮助将不胜感激.

推荐答案

(假设您在下面使用TS3.0或更高版本)

(Assuming you use TS3.0 or greater in the following)

TypeScript支持字符串文字类型的概念以及元组类型,因此可以得到您的值a以具有类型 ['ONE', 'TWO', 'THREE']以及 ['ONE', 'TWO', 'THREE'],如下所示:

TypeScript supports the concept of string literal types as well as tuple types, so it is possible to get your value a to have the type ['ONE', 'TWO', 'THREE'] as well as the value ['ONE', 'TWO', 'THREE'], like this:

const a: ['ONE', 'TWO', 'THREE'] = ['ONE', 'TWO', 'THREE'];

(稍后会出现一种较少重复的方法):

(A less redundant way to get this to happen will come later):

然后,您可以使用可以这样使用:

const b: SameValueAsKeys<typeof a> = a.reduce((acc, type) => ({ ...acc, [type]: type }), {} as any);
b.ONE; // property type is "ONE"
b.TWO; // property type is "TWO"
b.THREE; // property type is "THREE"

请注意,编译器如何知道b具有三个键,即"ONE""TWO""THREE",并且值与这些键相同.

Notice how the compiler knows that b has three keys, "ONE", "TWO", and "THREE", and that the values are the same as the keys.

因此TypeScript当然支持这种类型的动态类型.不幸的是,如上所示,使用起来有点繁琐.一种减少这种烦人的方法是添加一些帮助函数,这些函数允许编译器推断正确的类型,或者至少将类型断言隐藏在开发人员无需担心它们的库中.

So TypeScript certainly supports this type of dynamic typing. Unfortunately it's a bit tedious to use as I showed it above. One way to make this less annoying is to add some helper functions that allow the compiler to infer the proper types, or at least hide the type assertions in a library where the developer won't have to worry about them.

首先,对于a ...编译器不会推断出元组类型,并且除了

First, for a... the compiler doesn't infer tuple types, and it also tends to widen string literals to the string type except in certain instances. Let's introduce a helper function named stringTuple():

function stringTuple<T extends string[]>(...args: T) { return args; }

这推断出

This infers a tuple type from rest arguments. Now we can use it to make a without typing redundant string values:

const a = stringTuple("ONE", "TWO", "THREE");

接下来,让我们介绍一个函数,该函数获取字符串列表并返回一个对象,该对象的键是那些字符串,并且其值与这些字符串匹配:

Next, let's introduce a function which takes a list of strings and returns an object whose keys are those strings and whose values match the strings:

function keyArrayToSameValueAsKeys<T extends string[]>(keys: T): SameValueAsKeys<T>;
function keyArrayToSameValueAsKeys(keys: string[]): { [k: string]: string } {
  return keys.reduce((acc, type) => ({ ...acc, [type]: type }), {});
}

在这里,我们将您的代码与reduce一起使用,但是我们将其隐藏在自己的函数中,并使用单个

Here we are using your same code with reduce, but we're hiding it inside its own function and using a single overload call signature to represent the intended output type. Now, we can get b like this:

const b = keyArrayToSameValueAsKeys(a);
b.ONE; // property type is "ONE"
b.TWO; // property type is "TWO"
b.THREE; // property type is "THREE"

如果将stringTuple()keyArrayToSameValueAsKeys()放在库中,则用户可以轻松使用它们:

If you put stringTuple() and keyArrayToSameValueAsKeys() in a library, the user can use them without too much trouble:

const otherObject = keyArrayToSameValueAsKeys(stringTuple("x", "y", "z"));
// const otherObject: {X: "X", Y: "Y", Z: "Z"}

或者您可以像这样将它们合并在一起:

Or you can merge them together like this:

function keysToSameValueAsKeys<T extends string[]>(...keys: T): { [K in T[number]]: K };
function keysToSameValueAsKeys(keys: string[]): { [k: string]: string } {
  return keys.reduce((acc, type) => ({ ...acc, [type]: type }), {});
}

然后在一个调用中获得输出,如下所示:

And then get the output in one call, like this:

const lastOne = keysToSameValueAsKeys("tic", "tac", "toe");
// const lastOne: {tic: "tic", tac: "tac", toe: "toe"};


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


Okay, hope that's of some help. Good luck!

这篇关于TypeScript是否可以从动态对象推断键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆