TypeScript是否可以从动态对象推断键? [英] Is it possible for TypeScript to infer keys from a dynamic object?
问题描述
我要在这里实现的是从数组生成的对象的智能感知/自动完成-类似于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.
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屋!