[英]Is it possible for TypeScript to infer keys from a dynamic object?
我在這里想要實現的是從數組生成的對象的智能感知/自動完成-類似於Redux的Action Creator,可以將string[]
數組( string[]
)簡化為形狀為{ [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知道鍵是字符串,但不知道它們是什么。
interface ITypesReturnObject { [s: string]: string }
有沒有人想出一種方法來通知TypeScript對象上的鍵等於數組中的字符串?
任何幫助將不勝感激。
(假設您在下面使用TS3.0或更高版本)
打字稿支持的概念字符串文本類型 ,以及元組類型 ,因此它可以讓你的價值a
有型 ['ONE', 'TWO', 'THREE']
以及值 ['ONE', 'TWO', 'THREE']
,像這樣:
const a: ['ONE', 'TWO', 'THREE'] = ['ONE', 'TWO', 'THREE'];
(實現這一目標的一種不太冗長的方法將在以后出現):
然后,您可以使用映射類型將b
的預期類型表示為從鍵到與鍵完全匹配的值的映射 :
type SameValueAsKeys<KS extends string[]> = { [K in KS[number]]: K };
可以這樣使用:
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"
,並且值與這些鍵相同。
因此,TypeScript當然支持這種類型的動態類型。 不幸的是,如上所示,使用起來有點繁瑣。 減少煩人的一種方法是添加一些幫助程序函數,這些函數允許編譯器推斷正確的類型,或者至少將類型斷言隱藏在開發人員無需擔心它們的庫中。
首先, a
...編譯器不會推斷的元組類型,它也傾向於擴大字符串文字的string
類型,除了在某些情況下 。 讓我們介紹一個名為stringTuple()
的輔助函數:
function stringTuple<T extends string[]>(...args: T) { return args; }
這從其余參數推斷出元組類型 。 現在,我們可以使用它來創建a
而無需鍵入多余的字符串值:
const a = stringTuple("ONE", "TWO", "THREE");
接下來,讓我們介紹一個函數,該函數獲取字符串列表並返回一個對象,該對象的鍵是那些字符串,並且其值與這些字符串匹配:
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
相同的代碼,但將其隱藏在自己的函數中,並使用單個重載調用簽名來表示預期的輸出類型。 現在,我們可以這樣得到b
:
const b = keyArrayToSameValueAsKeys(a);
b.ONE; // property type is "ONE"
b.TWO; // property type is "TWO"
b.THREE; // property type is "THREE"
如果將stringTuple()
和keyArrayToSameValueAsKeys()
放在庫中,則用戶可以輕松使用它們:
const otherObject = keyArrayToSameValueAsKeys(stringTuple("x", "y", "z"));
// const otherObject: {X: "X", Y: "Y", Z: "Z"}
或者,您可以將它們合並在一起,如下所示:
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 }), {});
}
然后在一個調用中獲得輸出,如下所示:
const lastOne = keysToSameValueAsKeys("tic", "tac", "toe");
// const lastOne: {tic: "tic", tac: "tac", toe: "toe"};
好的,希望對您有所幫助。 祝好運!
如果您事先知道數組中將包含的內容,則可以執行以下操作:
type myType = 'ONE' | 'TWO' | 'THREE';
const a: myType[] = ['ONE', 'TWO', 'THREE'];
const b: { [key in myType]: myType } = a.reduce<{ [key in myType]: myType }>((acc, type) => ({ ...acc, [type]: type }), <any>{});
// correct intellisense
b.ONE === 'ONE'
來到這里尋找更好的答案。 這是我想出的,效果很好:
const makeStyles = <T extends string = string>(styles: Record<T, string>): Record<T, string> => {
return styles;
}
const classes = makeStyles({
hello: 'hello world',
another: 'something else'
})
/**
* now typescript will infer the keynames that appear in the object passed
* to makeStyles
*/
console.log(classes)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.