检查typescript中的深点符号路径
Typescript挑战(来自更复杂代码的简化示例)。。。拆分深层对象路径并键入检查原始字符串 这在typescript中是可能的,还是我必须编写运行时检查 更多详细信息请参见代码注释检查typescript中的深点符号路径,typescript,Typescript,Typescript挑战(来自更复杂代码的简化示例)。。。拆分深层对象路径并键入检查原始字符串 这在typescript中是可能的,还是我必须编写运行时检查 更多详细信息请参见代码注释 接口住宅{ 地址:字符串; 年份:数字; 所有者:{ 名称:字符串; } } 康斯特之家:住所={ 地址:'Type street 1', 年份:2010年, 所有者:{ 姓名:“约翰·史密斯”, }, }; 函数getProp(对象:T,键:K):T[K]{ 返回obj[键]; } //以下行按预期工作,包括为
接口住宅{
地址:字符串;
年份:数字;
所有者:{
名称:字符串;
}
}
康斯特之家:住所={
地址:'Type street 1',
年份:2010年,
所有者:{
姓名:“约翰·史密斯”,
},
};
函数getProp(对象:T,键:K):T[K]{
返回obj[键];
}
//以下行按预期工作,包括为不存在的键提供类型错误:
getProp(房屋,“地址”);
getProp(house,'year');
//@ts expect错误:正如预期的,因为“其他”不是居住区的一部分
getProp(house,“other”);
功能更深(目标:T,路径:P){
//这里的逻辑是不同的,重点是分割路径
//能够检查物体深层结构的每个部分
const firstProp=path.split('.')[0];
getProp(obj,firstProp);
}
//问题在于将平面关键点与深度路径组合时。是否可能出现以下情况,包括不存在路径的类型错误?
更深的(房子,“地址”);
更深的(房子,“业主”);
更深(房子,'owner.name');//应该可以工作,因为类型中存在深层路径
//@ts expect错误:属性“city”不在住宅中
更深的(房子,'城市');
//@ts expect错误:深度路径所有者.email未驻留
更深(house,'owner.email');
恐怕您不能准确地执行此操作,您必须传入字符串数组,下面是我们键入lodash-get的示例。(可能不是最漂亮的,但它很管用,我们不再需要新的打字脚本功能,比如新的typeguards和可选的链接)
您要查找的结果是什么,如果需要检查对象是否来自union,则应使用typeguards:
从“lodash”导入;
导出接口TypedExtractor{
(对象:T,键1:K1):T[K1];
(对象:T,key1:K1,key2:K2):T[K1][K2];
(对象:T,key1:K1,key2:K2,key3:K3):T[K1][K2][K3];
(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
):T[K1][K2][K3][K4];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
):T[K1][K2][K3][K4][K5];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]的键,
K6扩展了T[K1][K2][K3][K4][K5]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
键6:K6,
):T[K1][K2][K3][K4][K5][K6];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]的键,
K6扩展了T[K1][K2][K3][K4][K5]的键,
K7[K1][K2][K3][K4][K5][K6]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
键6:K6,
键7:K7,
):T[K1][K2][K3][K4][K5][K6][K7];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]的键,
K6扩展了T[K1][K2][K3][K4][K5]的键,
K7扩展了T[K1][K2][K3][K4][K5][K6]的键,
K8[K1][K2][K3][K4][K5][K6][K7]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
键6:K6,
键7:K7,
键8:K8,
):T[K1][K2][K3][K4][K5][K6][K7][K8];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]的键,
K6扩展了T[K1][K2][K3][K4][K5]的键,
K7扩展了T[K1][K2][K3][K4][K5][K6]的键,
K8扩展了T[K1][K2][K3][K4][K5][K6][K7]的键,
K9[K1][K2][K3][K4][K5][K6][K7][K8]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
键6:K6,
键7:K7,
键8:K8,
键9:K9,
):T[K1][K2][K3][K4][K5][K6][K7][K8][K9];
<
T
K1扩展了T的键,
K2扩展了T[K1]的键,
K3扩展了T[K1][K2]的键,
K4扩展了T[K1][K2][K3]的键,
K5扩展了T[K1][K2][K3][K4]的键,
K6扩展了T[K1][K2][K3][K4][K5]的键,
K7扩展了T[K1][K2][K3][K4][K5][K6]的键,
K8扩展了T[K1][K2][K3][K4][K5][K6][K7]的键,
K9扩展了T[K1][K2][K3][K4][K5][K6][K7][K8]的键,
K10扩展了T[K1][K2][K3][K4][K5][K6][K7][K8][K9]
>(
对象:T,
键1:K1,
键2:K2,
键3:K3,
键4:K4,
键5:K5,
键6:K6,
键7:K7,
键8:K8,
键9:K9,
键10:K10,
):T[K1][K2][K3][K4][K5][K6][K7][K8][K9][K10];
}
导出常量:TypedExtractor=(对象:任意,…键:(字符串|编号)[]):字符串|编号|对象|未定义=>{
返回u.get(对象、键);
};
使用TypeScript 4.1,使用模板文字类型几乎可以实现这一点
type NestedValueOf<Obj, Key extends string> =
Obj extends object ?
Key extends `${infer Parent}.${infer Leaf}` ?
Parent extends keyof Obj ?
NestedValueOf<Obj[Parent], Leaf>
: never
: Key extends keyof Obj ? Obj[Key] : never
: never
类型NestedValueOf=
Obj扩展对象?
键扩展了`${expert Parent}.${expert Leaf}`?
Obj的父对象?
嵌套值
:从不
:键扩展了Obj的键?绝对不会
:从不
用法:
interface Residence {
address: string;
year: number;
owner: {
name: string;
}
}
const house: Residence = {
address: 'Type street 1',
year: 2010,
owner: {
name: 'John Smith',
},
}
function getProp<T, Key extends string>(obj: T, key: Key): NestedValueOf<T, Key> {
// TODO
}
getProp(house, 'address') // string
getProp(house, 'owner') // { name: string }
getProp(house, 'owner.name') // string
getProp(house, 'city') // never
接口住宅{
地址:字符串;
年份:
interface Residence {
address: string;
year: number;
owner: {
name: string;
}
}
const house: Residence = {
address: 'Type street 1',
year: 2010,
owner: {
name: 'John Smith',
},
}
function getProp<T, Key extends string>(obj: T, key: Key): NestedValueOf<T, Key> {
// TODO
}
getProp(house, 'address') // string
getProp(house, 'owner') // { name: string }
getProp(house, 'owner.name') // string
getProp(house, 'city') // never