Typescript 如何定义允许嵌套属性键的类型

Typescript 如何定义允许嵌套属性键的类型,typescript,Typescript,我有一个具有多个属性的模型,每个属性都是子模型: 例: 我希望为函数读取(model,level1Key,level2Key){}提供正确的类型,如果level1Key和level2Key不匹配,则类型检查将失败。 前任: read(myModel'a','x')//确定,返回'foo' read(myModel,'b','y')//确定,返回'bar' read(myModel'a','y')//不正常,typescript将失败 类型ConferenceLocation={ 地址:字符串;

我有一个具有多个属性的模型,每个属性都是子模型:

例:

我希望为
函数读取(model,level1Key,level2Key){}
提供正确的类型,如果
level1Key
level2Key
不匹配,则类型检查将失败。 前任:
read(myModel'a','x')//确定,返回'foo'
read(myModel,'b','y')//确定,返回'bar'
read(myModel'a','y')//不正常,typescript将失败

类型ConferenceLocation={
地址:字符串;
城市:字符串;
邮编:号码;
状态:字符串;
};
类型ConferenceDescription={
名称:字符串;
来源:字符串;
到:字符串;
};
类型会议={
描述:会议描述;
地点:会议地点;
};
const会议:会议={
说明:{
名称:“CES-拉斯维加斯2020”,
从:“2020-01-07T00:00:00Z”,
致:“2020-01-10T00:00:00Z”
},
地点:{
地址:天堂路3150号,
城市:“拉斯维加斯”,
邮政编码:89109,
国家:“NV”
}
};
函数读取(
会议:会议,
物业:会议中心,
关键字:字符串
):无效{
document.writeln(
会议和会议[property]和会议[property][key]
);
书面文件(“
”); } 阅读(会议,“说明”、“名称”); 阅读(会议,“地点”、“城市”); 阅读(会议,“描述”、“城市”); 阅读(会议,“元”、“城市”);
我们可以在这里看到:

传输程序正在为
read(会议,“元”,“城市”)引发错误“meta”
不是有效的
会议密钥

但是当我将参数
key
定义为
字符串时,它允许
读取(会议,“描述”,“城市”),将在运行时失败


你知道如何做到这一点吗?或者甚至有可能吗?

这里的问题是,您要求Typescript编译器“深入”您的代码以发现问题。这不是一个完全不合理的期望,但它比Typescript所能处理的稍微多一些

考虑一下你失败的例子:

read(conference, "meta", "city");
在这种情况下,Typescript可以轻松确定
meta
无效,因为它不在会议的
keyof
中。这是直截了当的,因为它有明确的定义

但在另一个例子中:

read(conference, "description", "city");
您可能希望它查看
conference.description
的类型,并看到未设置
city
属性

但为了做到这一点,它需要评估
会议[属性]
以确定该值的类型,然后检查
键所表示的属性是否存在。不幸的是,它无法做到这一点,因为运行时之前不知道
属性

“但是,”你说。“该值是已知的-它在代码中被指定为常量。”

这是事实,但归根结底是这一行代码:

document.writeln(
    conference && conference[property] && conference[property][key]
);

为了确定会议[属性]
的类型,Typescript需要执行该代码。这是Typescript所不能做到的——它是静态代码分析的工具。

这里的问题是,您要求Typescript编译器“深入”您的代码以发现问题。这不是一个完全不合理的期望,但它比Typescript所能处理的稍微多一些

考虑一下你失败的例子:

read(conference, "meta", "city");
在这种情况下,Typescript可以轻松确定
meta
无效,因为它不在会议的
keyof
中。这是直截了当的,因为它有明确的定义

但在另一个例子中:

read(conference, "description", "city");
您可能希望它查看
conference.description
的类型,并看到未设置
city
属性

但为了做到这一点,它需要评估
会议[属性]
以确定该值的类型,然后检查
键所表示的属性是否存在。不幸的是,它无法做到这一点,因为运行时之前不知道
属性

“但是,”你说。“该值是已知的-它在代码中被指定为常量。”

这是事实,但归根结底是这一行代码:

document.writeln(
    conference && conference[property] && conference[property][key]
);

为了确定会议[属性]
的类型,Typescript需要执行该代码。这是Typescript所不能做到的——它是静态代码分析的工具。

您可以使用Typescript函数重载来实现您的目标。重载将按顺序处理,直到检查成功为止。要为您的方法提供类型检查,我建议如下:

function read(
  conference: Conference,
  property: "description",
  key: keyof ConferenceDescription
): void;

function read(
  conference: Conference,
  property: "location",
  key: keyof ConferenceLocation
): void;

function read(
  conference: Conference,
  property: "location" | "description",
  key: keyof ConferenceDescription | keyof ConferenceLocation): void {
    document.writeln(
      conference && conference[property] && conference[property][key]
    );
    document.writeln("<br />");
}

read(conference, "description", "name"); //OK
read(conference, "location", "city");    //OK
read(conference, "description", "city"); //BAD
read(conference, "meta", "city");        //BAD
函数读取(
会议:会议,
属性:“说明”,
关键字:keyof conference description
):无效;
函数读取(
会议:会议,
属性:“位置”,
关键字:会议地点关键字
):无效;
函数读取(
会议:会议,
属性:“位置”|“说明”,
key:keyof ConferenceDescription | keyof ConferenceLocation):无效{
document.writeln(
会议和会议[property]和会议[property][key]
);
书面文件(“
”); } 阅读(会议,“说明”、“名称”)//好啊 阅读(会议,“地点”、“城市”)//好啊 阅读(会议,“描述”、“城市”)//坏的 阅读(会议,“元”、“城市”)//坏的
您可以使用Typescript函数重载来实现您的目标。重载将按顺序处理,直到检查成功为止。要为您的方法提供类型检查,我建议如下:

function read(
  conference: Conference,
  property: "description",
  key: keyof ConferenceDescription
): void;

function read(
  conference: Conference,
  property: "location",
  key: keyof ConferenceLocation
): void;

function read(
  conference: Conference,
  property: "location" | "description",
  key: keyof ConferenceDescription | keyof ConferenceLocation): void {
    document.writeln(
      conference && conference[property] && conference[property][key]
    );
    document.writeln("<br />");
}

read(conference, "description", "name"); //OK
read(conference, "location", "city");    //OK
read(conference, "description", "city"); //BAD
read(conference, "meta", "city");        //BAD
函数读取(
会议:会议,
属性:“说明”,
关键字:keyof conference description
):无效;
函数读取(
会议:会议,
属性:“位置”,
关键字:会议地点关键字
):无效;
函数读取(
会议:会议,
属性:“位置”|“说明”,
密钥:keyof conference