如何声明 TypeScript 接口,其中属性名称是数组中的值



我正在尝试为具有设置对象的库创建一个.d.ts文件,该库允许开发人员提供另一个对象,其中包含将调用以执行日志记录的函数。

像这样:

type LogFunction = (message?: any, ...optionalParams: any[]) => void;
interface Logger {
warn: LogFunction;
log: LogFunction;
// several more methods here
}
interface Settings {
logger?: Logger;
}

只要函数属性命名为warnlog等,此接口就可以工作。 但是,此设置对象还允许开发人员传入其他名称以用于属性/函数。 例如,我可以通过如下所示的代码告诉它调用名为anotherName的属性/函数的名称,而不是使用warn作为要调用的属性/函数的名称。

const settings = {
logger: {  anotherName: function() { .... } },
logLevelMethods: [ "anotherName" ]
}

如何编写这种类型的声明?

我知道 TS 2.9 实现了对使用符号作为属性名称的某种级别的支持,但我找不到将数组中的值与日志记录对象中的键名称相关联的方法。

我忽略了它吗?

谢谢!

如果有帮助,我正在尝试为jquery-mockjaxjquery 插件编写一个声明。

您需要使用泛型和映射类型来实现此目的。您可以将Logger定义为映射类型,该类型接受的类型将是其键的联合:

type Logger<T extends  string | symbol| number >  = { [P in T]: LogFunction}

您可以将类型从Settings转发到Logger

interface Settings<T extends string | symbol| number = "log" | "warn"| "error"> {
logger?: Logger<T>;
logLevelMethods: T[]
}

声明实例时,通常需要指定类型参数:

const simple: Settings<"log" | "warn"| "error"> = {
logLevelMethods: [], // while this can contain the names, it does not have to unfortunately
logger: {
error: () => {},
warn: () => {},
log: () => {},
}
}

更好的解决方案是创建一个函数来帮助我们创建一个设置对象:

function createSettings<T extends string | symbol | number >(settings: Settings<T> ){
return settings;
}
const otherSymbol = Symbol("Test");
const settings = createSettings({
logLevelMethods : ["warn", "other", "new", 0, otherSymbol],
logger: {
0 : ()=>{},
// 1 : ()=>{}, // This would be an error
// log: ()=> {}, // Also an error not in the array 
warn: ()=> {},
other: () => {},
new: ()=> {},
[otherSymbol]: ()=> {}
}
})

这也具有强制执行数组和记录器成员同意的约束的优点(前提是没有将显式参数传递给函数(

注意:我使用了string | symbol| number因为这是2.9中键的最大允许域,您可以删除此联合中的任何成员以支持该类型的键(例如,删除number以禁止数字键(

最新更新