TypeScript:将对象条目映射到类型
Posted
技术标签:
【中文标题】TypeScript:将对象条目映射到类型【英文标题】:TypeScript: Mapping object entries to types 【发布时间】:2020-11-25 16:27:15 【问题描述】:作为一个新手打字稿用户,我什至无法提出问题,所以请多多包涵。
我正在尝试创建一个键 => [string + valueObject 接口] 字符串和 valueObjects 的映射(作为一种类型),然后有一个函数,它根据传递的键强制执行 valueObject 接口。
我觉得最好用一个例子来解释:
// This is an pseudo example stub, not actually working
type ReplaceableWith<T> = string;
// ^ the type I'd like to enforce as the argument
const templates =
// templateId // template // define somehow the interface required for this template
'animal.sound': 'A animal goes sound' as ReplaceableWith< animal: string; sound: string>
;
function renderTemplate(
templateId , // must be a key of templates
params // must match value object type, based on templateId
): string
let rendered = templates[templateId];
for (const [key, value] of Object.entries(params))
// replace keys from template with values
rendered = rendered.replace('' + key + '', value);
return rendered;
const a = renderTemplate('animal.sound', animal: 'Dog', sound: 'woof' )
// ^ a = 'A Dog goes woof'
const b = renderTemplate('animal.sound', name: 'Some' );
// ^ should throw TS error
显然,这个例子不起作用,但我认为它展示了我想要实现的目标。我对 keyof、泛型和枚举进行了一些未受过教育的尝试,但没有成功。
这种类型映射(或查找)是否可能?
更新(工作示例)
经过一番尝试,下面是一个具有潜在解决方案的工作示例:
type TemplateKeys =
'animal.sound': animal: string; sound: string ;
'animal.sleep': location: string ;
'animal.herd': expectedCount: number; available: number ;
'animal.think': undefined;
;
const templates: [key in keyof TemplateKeys]: string =
'animal.sound': 'animal goes sound',
'animal.sleep': 'It sleeps in location',
'animal.herd': 'There is available animals out of expectedCount',
'animal.think': 'Its thinking'
;
function renderTemplate<K extends keyof TemplateKeys>(key: K, params?: TemplateKeys[K]): string
if (params !== undefined)
//@ts-ignore
return Object.entries(params).reduce((previousValue: string, [param, value]: [string, any]) =>
return previousValue.replace('' + param + '', value);
, templates[key]);
return templates[key];
console.log(renderTemplate('animal.sound', animal: 'Dog', sound: 'woof' ));
console.log(renderTemplate('animal.sleep', location: 'a hut' ));
console.log(renderTemplate('animal.herd', expectedCount: 20, available: 10 ));
console.log(renderTemplate('animal.think'));
输出:
[LOG]: Dog goes woof
[LOG]: It sleeps in a hut
[LOG]: There is 10 animals out of 20
[LOG]: Its thinking
虽然这可行,但它有两个问题:
-
我必须定义两次键(在界面和实例中)。
参数界面和消息是分开的,理想情况下应该放在一起。
【问题讨论】:
进行了更新。请看一下 【参考方案1】:2021 年 9 月 17 日更新
我已经删除了所有重复的代码。
我还创建了一个允许参数的联合 - Params
。请查看更新示例
const enum Animal
sound = 'animal.sound',
sleep = 'animal.sleep',
herd = 'animal.herd',
think = 'animal.think',
type TemplateKeys =
[Animal.sound]: animal: string; sound: string ;
[Animal.sleep]: location: string ;
[Animal.herd]: expectedCount: number; available: number ;
[Animal.think]?: string;
;
const templates =
[Animal.sound]: 'animal goes sound',
[Animal.sleep]: 'It sleeps in location',
[Animal.herd]: 'There is available animals out of expectedCount',
[Animal.think]: 'Its thinking'
as const;
type Templates = typeof templates;
type Values<T> = T[keyof T]
type Dictionary =
[Prop in keyof TemplateKeys]:
(key: Prop, params: TemplateKeys[Prop]) => string
type Params =
Parameters<
NonNullable<
Values<Dictionary>
>
>
const renderTemplate = (...params: Params) =>
const [key, ...props] = params;
if (props !== undefined)
// @ts-ignore
const result = (Object.entries(props) as Array<Params>)
.reduce<string>((previousValue, [param, value]) =>
typeof value === 'string'
? previousValue.replace('' + param + '', value)
: previousValue,
templates[key]
);
return result
return templates[key];
renderTemplate(Animal.sleep, location: 'a hut' ) // ok
renderTemplate(Animal.herd, expectedCount: 20, available: 10 ) // ok
renderTemplate(Animal.sound, location: 'sd' ) // expected error
我为键创建了Animal
枚举。不用担心,枚举不会包含在您的捆绑包中。
这是payground的链接 这是Object.entries typings的链接
说明:
Dictionary
- 主要的实用程序类型。它使用Animal
键和函数作为值创建一个对象。这个函数已经考虑了特定键的允许道具。
例子:
type Dictionary =
"animal.sound": (key: Animal.sound, params:
animal: string;
sound: string;
) => string;
"animal.sleep": (key: Animal.sleep, params:
location: string;
) => string;
"animal.herd": (key: Animal.herd, params:
expectedCount: number;
available: number;
) => string;
"animal.think"?: ((key: Animal.think, params: string | undefined) => string) | undefined;
现在,我们需要将此数据结构转换为具有两个元素的元组。第一个元素 - 一个键,第二个元素 - 是允许的参数。
你可能会问:为什么我们需要一个元组?因为rest
参数是一个元组。
所以我们只需要借助@987654330@ 实用程序获取所有值,并借助内置实用程序Parameters
获取它们的参数:
type Params =
| [Animal.sound,
animal: string;
sound: string;
]
| [Animal.sleep,
location: string;
]
| [Animal.herd,
expectedCount: number;
available: number;
]
| [Animal.think, string | undefined]
type Params =
Parameters<
NonNullable<
Values<Dictionary>
>
>
【讨论】:
以上是关于TypeScript:将对象条目映射到类型的主要内容,如果未能解决你的问题,请参考以下文章