- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试构建翻译服务。用于翻译标签的函数应该提供对可能标签的类型检查,以及基于给定标签的替换对象。
我有一个标签列表对象,它描述了可能的标签和应该出现在翻译后的字符串中的占位符列表。
export const TagList = {
username_not_found: ['username']
};
在这种情况下,关键是字典应该实现的标签名称。该值是应出现在已翻译字符串中的占位符列表。
字典看起来有点像这样:
// Note: The type declaration of keys don't work this way (key should be number or string). Not sure how I should implement this...
const en: {[name: keyof (typeof TagList)]: string} = {
"username_not_found": "The user {username} does not exist"
}
用于翻译标签的方法如下:
this.trans("username_not_found", {username: "someone@example.com"});
我想要实现的是在我的 IDE 中对占位符对象进行类型检查(自动完成),以强制配置所有占位符。
例如:
// This is wrong: "username" placeholder is not specified.
this.trans("username_not_found", {});
// This is also wrong: "foobar" is a non-existing placeholder.
this.trans("username_not_found", {foobar: "42"});
// This is good:
this.trans("username_not_found", {username: "someone@example.com"});
目前我正在使用 keyof (typeof TagList)
作为 tagName
的参数类型。我不确定这是否是正确的方法,但它确实有效。我现在正在寻找一种方法来根据第一个参数中给定的值推断第二个参数的对象结构。
我试图避免必须维护多个可能的标记列表(例如,必须同时在接口(interface)和对象中声明它们)。
提前致谢!
最佳答案
首先,您需要使 TagList 不可变。
然后我就创建了基于键的文字类型。非常类似于Array.prototype.reduce
export const TagList = {
username_not_found: ['username'],
username_found: ['name'],
batman: ['a', 'b']
} as const;
type Elem = string
type Reducer<
Arr extends ReadonlyArray<Elem>, // array
Result extends Record<string, any> = {} // accumulator
> = Arr extends [] ? Result // if array is empty -> return Result
: Arr extends readonly [infer H, ...infer Tail] // if array is not empty, do recursive call with array Tail and Result
? Tail extends ReadonlyArray<Elem>
? H extends Elem
? Reducer<Tail, Result & Record<H, string>>
: never
: never
: never;
type TagList = typeof TagList;
const trans = <Tag extends keyof TagList, Props extends Reducer<TagList[Tag]>>(tag: Tag, props: Props) => null as any
trans("username_not_found", { username: "someone@example.com" }); // ok
trans("username_found", { name: "John" }); // ok
trans("batman", { a: "John", b: 'Doe' }); // ok
trans("username_not_found", { name: "someone@example.com" }); // expected error
trans("username_found", { username: "John" }); // expected error
这里的主要目标是将元组 ['username']
转换为 { username: string }
在纯 js 中你会怎么做?
['username'].reduce((acc, elem) => ({ ...acc, [elem]: 'string' }), {})
我使用的是几乎相同的算法,但使用的是递归而不是迭代。
这是 Reducer
实用程序类型的 js 模拟
const reducer = (arr: ReadonlyArray<Elem>, result: Record<string, any> = {}): Record<string, any> => {
if (arr.length === 0) {
return result
}
const [head, ...tail] = arr;
return reducer(tail, { ...result, [head]: 'string' })
}
您可以在我的blog 中找到更多信息
关于 typescript 根据先前参数的值推断可能的对象键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68207767/
我的应用将 SceneKit 内容的“页面”与图像和文本交替。当我从图像页面前进到新的 SceneKit 页面时,前一个 SceneKit 页面中的内容会短暂显示,然后被新内容替换。时髦。 我只使用一
我正在尝试处理(在 C# 中)包含一些数字数据的大型数据文件。给定一个整数数组,如何对其进行拆分/分组,以便如果下一个 n(两个或更多)是负数,则前一个 n 元素被分组。例如,在下面的数组中,应该使用
刚接触promises,研究过。所以我的代码和我的理解: sql.connect(config).then(function(connection) { return connection.req
目前我在 if (roobaf) block 中有一些代码,这取决于 foo 和 bar 是否为假。我可以在 block 内再次检查这些条件,但感觉像是不必要的代码重复。 if (foo) {
我是一名优秀的程序员,十分优秀!