typescript - 如何通过拆分字符串来推断嵌套对象值中的字符串文字?
问题描述
我正在尝试根据您在对象中定位的路径来构建所需的对象参数
type Split<S extends string, D extends string> =
string extends S ? string[] :
S extends '' ? [] :
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
[S];
type PropType<T, Path extends string> =
string extends Path ? unknown :
Path extends keyof T ? T[Path] :
Path extends `${infer K}.${infer R}` ? K extends keyof T ? PropType<T[K], R> : unknown :
unknown;
type ParseMustaches_<T extends string> =
T extends `${infer U}{{${infer V}}}${infer W}`
? Record<V, string>
: never
type ParseMustaches<T extends string[]> = ParseMustaches_<T[number]>;
type Prop<T, K extends keyof T> = T[K];
declare function translate<T extends { [L in K]: string }, K extends string>(obj: T, path: K, placeholders: ParseMustaches<Split<T[K], " ">>): void;
const obj = {
"title": "Welcome to {{sitename}}, {{user}}",
"button": {
"text": "Click here to go to {{location}}",
"num": 5
}
} as const;
translate(obj, "title", { sitename: "", user: "" }) // works
translate(obj, "button.text", { }) // does not work
它似乎适用于顶级属性,但嵌套属性失败,我该如何解决这个问题? 链接到游乐场
解决方案
问题出在您所说的部分T extends { [L in K]: string }
,因为K
这里通常不是键,而是路径。所以你需要一些额外的工作来让你的魔法发生。
type Split<S extends string, D extends string> =
string extends S ? string[] :
S extends '' ? [] :
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
[S];
type PropType<T, Path extends string> =
string extends Path ? unknown :
Path extends keyof T ? T[Path] :
Path extends `${infer K}.${infer R}` ? K extends keyof T ? PropType<T[K], R> : unknown :
unknown;
type ParseMustaches_<T extends string> =
T extends `${infer U}{{${infer V}}}${infer W}`
? Record<V, string>
: never
type ParseMustaches<T extends string[]> = ParseMustaches_<T[number]>;
// You need to this utility type
type TypeOnPath<Path extends string, T> =
string extends Path ? unknown :
Path extends `${infer K}.${infer R}` ? { [k in K]: TypeOnPath<R, T> } :
{ [k in Path]: T };
declare function translate<K extends string, T extends TypeOnPath<K, string>>
(obj: T, path: K, placeholders: ParseMustaches<Split<PropType<T, K> & string, " ">>): void;
const obj = {
"title": "Welcome to {{sitename}}, {{user}}",
"button": {
"text": "Click here to go to {{location}}",
"num": 5
}
} as const;
translate(obj, "title", { sitename: "", user: "" })
translate(obj, "button.text", {}) // now we have an error saying that 'location' is missing
translate(obj, "button.num", {}) // correctly report error saying 'button.num' is not a string
看到这个游乐场链接
更新
要获得评论中提到的所需行为,您可以修改Split
:
// Remove constraint on S so that it takes any input type
type Split<S, D extends string> =
S extends string ? (
string extends S ? string[] :
S extends '' ? [] :
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
[S]
) : never;
type PropType<T, Path extends string> =
string extends Path ? unknown :
Path extends keyof T ? T[Path] :
Path extends `${infer K}.${infer R}` ? K extends keyof T ? PropType<T[K], R> : unknown :
unknown;
type ParseMustaches_<T extends string> =
T extends `${infer U}{{${infer V}}}${infer W}`
? Record<V, string>
: never
type ParseMustaches<T extends string[]> = ParseMustaches_<T[number]>;
type TypeOnPath<Path extends string, T> =
string extends Path ? unknown :
Path extends `${infer K}.${infer R}` ? { [k in K]: TypeOnPath<R, T> } :
{ [k in Path]: T };
// This time we use TypeOnPath<K, any>
declare function translate<K extends string, T extends TypeOnPath<K, any>>
(obj: T, path: K, placeholders: ParseMustaches<Split<PropType<T, K>, " ">>): void;
const obj = {
"title": "Welcome to {{sitename}}, {{user}}",
"button": {
"text": "Click here to go to {{location}}",
"num": 5
}
} as const;
translate(obj, "title", { sitename: "", user: "" })
translate(obj, "button.text", {}) // now we have an error saying that 'location' is missing
translate(obj, "button.num", {}) // error with never
看到这个游乐场链接
推荐阅读
- vue.js - 启动 VueJS 应用程序时 JavaScript 未启用错误
- javascript - 除了 v-toolbar 之外,还有其他方法可以修复 Vuetify 中的元素吗?
- java - 100% 不可变,但仍然不是线程安全的
- react-native - 反应原生的后退按钮
- javascript - 我可以在 Styled Componet 中设置 Child 的 css 吗?
- html - 具有 select2 和 css 定位的引导输入组
- npm - 按关键字和作者查找 NPM 包
- jquery - 更改页面加载时没有值的下拉选项文本
- css - 自定义滑块设计问题
- java - 我是否需要第三方接口的实现才能完成我的代码?