Typescript 如何将模板文字类型用于强类型;获取属性路径“;功能
我正在玩弄模板文字类型,试图让我的头脑包围它们,但我不太明白我希望这是一个简单的练习:一个强类型函数,其中Typescript 如何将模板文字类型用于强类型;获取属性路径“;功能,typescript,Typescript,我正在玩弄模板文字类型,试图让我的头脑包围它们,但我不太明白我希望这是一个简单的练习:一个强类型函数,其中get(obj,'foo.bar.baz')返回obj.foo.bar.baz的类型。(这是一个垫脚石,能够以某种方式强力键入我的作品的自制验证程序+消毒剂库,该库使用点分隔路径来指示嵌套属性 我的第一个方法是: type GetResult<Value, Path> = Path extends `${infer Pre}.${infer Post}` ? (Value
get(obj,'foo.bar.baz')
返回obj.foo.bar.baz
的类型。(这是一个垫脚石,能够以某种方式强力键入我的作品的自制验证程序+消毒剂库,该库使用点分隔路径来指示嵌套属性
我的第一个方法是:
type GetResult<Value, Path> = Path extends `${infer Pre}.${infer Post}`
? (Value extends {Pre: infer InnerValue} ? GetResult<InnerValue, Post> : undefined)
: (Value extends {Path: infer Result} ? Result : undefined);
function get<V, P>(val: V, path: P): GetResult<V, P> {
// @ts-ignore
return;
}
const val = {
foo: {
bar: {
quux: 123
}
}
}
const quux = get(val, 'foo');
我在这里哪里出错了?您的问题是类型
{Pre:any}
有一个带有文本字符串值的键“Pre”
;它不是一个带有Pre
类型键的字符串。表示您需要一个类似{[K in Pre]:any}的字符串
或等效的记录
。如果你解决了这个问题,我想你会取得一些进展
现在,突然出现标题中的问题,即 如何为强类型“get property path”函数使用模板文字类型 我给使用虚线路径的“深度索引”函数打字的方式可能如下所示:
type DeepIndex<T, K extends string> = T extends object ? (
string extends K ? never :
K extends keyof T ? T[K] :
K extends `${infer F}.${infer R}` ? (F extends keyof T ?
DeepIndex<T[F], R> : never
) : never
) : never
type ValidatePath<T, K> =
K extends string ? DeepIndex<T, K> extends never ? never : K : never;
declare const get: <T, K extends string>(
object: T,
keyName: K & ValidatePath<T, K>
) => DeepIndex<T, K>;
我肯定有一些边缘情况。例如,如果你的任何属性的名称中有一个“
”,那你就倒霉了。我希望像{“foo.bar”:{“baz.quox”:123}
这样的东西在这里做非常糟糕的事情。但至少它表明了一般的方法,一个在处拆分字符串的递归类型函数
字符,可以工作
simpleGet
在您提供的示例中返回未定义的,这可能是issue@BooklynDadCore是的,我知道。为什么它会返回它,而不是val.foo
的类型?在这个示例中,函数没有逻辑,只有一个返回。哦,天哪,你是对的,被语法高亮显示匹配它们愚弄了
type DeepIndex<T, K extends string> = T extends object ? (
string extends K ? never :
K extends keyof T ? T[K] :
K extends `${infer F}.${infer R}` ? (F extends keyof T ?
DeepIndex<T[F], R> : never
) : never
) : never
type ValidatePath<T, K> =
K extends string ? DeepIndex<T, K> extends never ? never : K : never;
declare const get: <T, K extends string>(
object: T,
keyName: K & ValidatePath<T, K>
) => DeepIndex<T, K>;
const val = {
foo: {
bar: {
quux: 123
}
}
}
const barQuuxNumber = get(val, 'foo'); // {bar: {quux: number}};
const num = get(val, 'foo.bar.quux'); // number