【发布时间】:2022-12-18 16:39:53
【问题描述】:
我想创建一个简单的辅助函数来从这样的对象中读取路径:
interface Human {
address: {
city: {
name: string;
}
}
}
const human: Human = { address: { city: { name: "Town"}}};
getIn<Human>(human, "address.city.name"); // Returns "Town"
这个助手在 JS 中很容易创建,但在 TS 中使其类型安全有点复杂。我已经走到这一步了:
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, ...0[]];
type Join<K, P> = K extends string | number
? P extends string | number
? `${K}${"" extends P ? "" : "."}${P}`
: never
: never;
type Path<T, D extends number = 4> = [D] extends [never]
? never
: T extends object
? {
[K in keyof T]-?: K extends string | number
? `${K}` | Join<K, Path<T[K], Prev[D]>>
: never;
}[keyof T]
: "";
function getIn<T extends Record<string, any>>(object: T, path: Path<T>): T {
const parts = path.split(".");
return parts.reduce<T>((result, key) => {
if (result !== undefined && result[key]) {
return result[key];
}
return undefined;
}, object);
}
这行得通,但这里的错误是getIn 的返回类型不应该是T,而是T 中的某些内容,具体取决于给定的路径。所以如果这样调用:
getIn<Human>(human, "address.city.name"); // Returns "Town"
TypeScript 现在应该返回值是一个字符串,如 Human 接口中定义的那样。如果给定"address.city",返回类型应该是City等。
有什么方法可以使其类型安全吗?
【问题讨论】:
-
this approach 是否满足您的需求?如果是这样,我可以写一个答案来解释;如果没有,我错过了什么?
-
哇,酷极了!这看起来正是我需要的。你是一位多么出色的 TypeScript 大师。 :)
-
好的,我会在有机会的时候写一个答案。
标签: typescript typescript-typings typescript-generics