如何在TypeScript中提示嵌套对象的键?



我有一些接口都扩展了基接口。例句:

interface Base {
sharedKey : "a" | "b"
}
interface ChildOne extends Base {
sharedKey : "a",
keyOne : "child_one"
}
interface ChildTwo extends Base {
sharedKey : "b",
keyTwo : "child_two"
}

所有的扩展接口都定义了一个共享键来缩小定义范围。我正在尝试实现我在许多ide中看到的一个特性,该特性提示嵌套对象的键。考虑这样一个函数:

function doStuff( sharedKey, privateKey ) { // Something here};

此函数将接受ab的密钥,并根据该密钥检测privateKey是否允许为keyOnekeyTwo

例如:

doStuff( 'a', 'keyOne' ); // Allowed

但不应该这样:

doStuff( 'b', 'keyOne' ); // Error: keyOne does not exist on ChildTwo

这可能吗?我尝试使用模板字面量,但问题是,从模板字面量返回的类型是一个字符串,我不能使用它作为一个类型。

使用Record<Unions['sharedKey'], Unions>(其中Unions是子接口的联合)为提供了一些键入提示,这有助于防止根本不存在的键,但仍然允许使用来自其他接口的键。

一个可能的解决方案是使用函数重载:

interface ChildOne {
sharedKey : "a",
keyOne : "child_one"
}
interface ChildTwo {
sharedKey : "b",
keyTwo : "child_two"
}
function doStuff( sharedKey: ChildOne['sharedKey'], privateKey: keyof ChildOne ):number
function doStuff( sharedKey: ChildTwo['sharedKey'], privateKey: keyof ChildTwo ):number
function doStuff( sharedKey: string, privateKey: string) { 
// Something here
return 0;
};
doStuff( 'a', 'keyOne' ); // Allowed
doStuff( 'b', 'keyOne' ); // Error: keyOne does not exist on ChildTwo

这可以通过Extract:

以可扩展的方式完成
function doStuff<
SharedKey extends Union["sharedKey"],
PrivateKey extends Exclude<keyof Extract<Union, { sharedKey: SharedKey }>, "sharedKey">
>(sharedKey: SharedKey, privateKey: PrivateKey) { ... }

其中Union是所有子节点的并集。

您获得正在使用的共享键,然后使用该键从联合中提取具有该键的子节点。

一旦你有了正确的子元素,你就会得到那个子元素的键值,不包括"sharedKey"(除非您还希望sharedKey在类型提示中显示?)。

从本质上讲,这与@PabloCarrilloAlvarez的回答表达为泛型的想法基本相同。

doStuff("a", "keyOne") // good
doStuff("b", "keyOne") // error
doStuff("b", "keyTwo") // good
doStuff("a", "keyTwo") // error

您可以通过以下几个示例调用尝试此方法:

游乐场

最新更新