TypeScript:基于上一个参数的参数类型

TypeScript:基于上一个参数的参数类型,typescript,generics,Typescript,Generics,我想实现函数参数的类型检查,其中第二个参数的属性基于前一个参数的属性 config变量应仅包含values数组中对象中存在的属性。属性应该是可选的(不需要在config中包含所有属性,但不允许添加不同的属性 请参见示例代码: 类型CustomType={ [K in keyof T]:编号 }; 类型配置={ [K in keyof T]?:{ 高优先级:布尔; 回调:(值:any[])=>number[]; } }; const customFunction=(值:T[],config:co

我想实现函数参数的类型检查,其中第二个参数的属性基于前一个参数的属性

config
变量应仅包含
values
数组中对象中存在的属性。属性应该是可选的(不需要在
config
中包含所有属性,但不允许添加不同的属性

请参见示例代码:

类型CustomType={
[K in keyof T]:编号
};
类型配置={
[K in keyof T]?:{
高优先级:布尔;
回调:(值:any[])=>number[];
}
};
const customFunction=(值:T[],config:config):数组=>{
//逻辑。。。
返回[];
};
常量值=[
{
福:‘福’,
酒吧:“酒吧”
},
{
福:‘福’,
酒吧:“酒吧”
}
];
//在本例中,应选择仅包含“foo”、“bar”属性
常量配置={
傅:{
高优先级:正确,
回调:()=>[]
},
//不存在于值对象中
错:{
高优先级:正确,
回调:()=>[]
}
};
//配置应标记为错误,因为值对象中不存在“错误”

const result=customFunction(values,config);
Typescript仅当您将对象文字直接指定给给定类型的变量/参数时,才检查多余的属性,如文档所述。在您的情况下,您可以显式键入
config
,或直接将对象文字用作参数:

const values = [
    {
        foo: 'foo',
        bar: 'bar'
    },
    {
        foo: 'foo',
        bar: 'bar'
    }
];

// We type relative to values, no need for the extra interface
const config: Config<typeof values[number]> = {
    foo: {
        highPriority: true,
        callback: () => []
    },
    // will be an error
    wrong: {
        highPriority: true,
        callback: () => []
    }
};

//Or pass the object literal directly 
const result2 = customFunction(values, {
    foo: {
        highPriority: true,
        callback: () => []
    },
    // error
    wrong: {
        highPriority: true,
        callback: () => []
    }
});
const值=[
{
福:‘福’,
酒吧:“酒吧”
},
{
福:‘福’,
酒吧:“酒吧”
}
];
//我们输入的是相对值,不需要额外的接口
常量配置:配置={
傅:{
高优先级:正确,
回调:()=>[]
},
//这将是一个错误
错:{
高优先级:正确,
回调:()=>[]
}
};
//或者直接传递对象文本
const result2=自定义函数(值{
傅:{
高优先级:正确,
回调:()=>[]
},
//错误
错:{
高优先级:正确,
回调:()=>[]
}
});
另一个选项是,如果传递的类型具有额外属性,则使用条件类型和额外参数触发错误:

type NoExtraProperties<TSource, TTarget> = Exclude<keyof TSource, keyof TTarget> extends never ? true : "Extra properties detected";
const customFunction = <T, TConfig extends Config<T>>(values: T[], config: TConfig, validate: NoExtraProperties<TConfig, T>): Array<CustomType<T>> => {
    // logic...

    return [];
};

// Argument of type 'true' is not assignable to parameter of type '"Extra properties detected"'.
const result = customFunction(values, config, true); 
type NoExtraProperties=Exclude extends never?true:“检测到额外属性”;
const customFunction=(值:T[],配置:TConfig,验证:NoExtraProperties):数组=>{
//逻辑。。。
返回[];
};
//类型为“true”的参数不能分配给类型为“检测到额外属性”的参数。
const result=customFunction(值、配置、真);

游戏场

旁注:您的泛型类型似乎根本不关心
t
中属性值的类型。如果这是真的,您最好在键中使它们泛型(例如,
type CustomType={[p in K]:number}在<代码> k>代码>中,您的函数将是通用的,如果需要,代码< > t>代码>被代码< >记录> /代码>代替。它确实不考虑<代码> t>代码>中的值类型。但是在第一个例子中,我得到错误消息<代码>类型“t”不满足约束“字符串”。< /代码>确实如此。更有意义?这几乎正是我想要实现的!但是现在'values'的属性名称依赖于
config
的属性名称-我更希望它是相反的-
config
属性名称应该依赖于
values
属性名称。谢谢你的回答,我不知道passin之间的区别g直接输入变量和对象文本。不幸的是,我没有完全指定我的当前条件:-
config
在别处定义,不知道
变量(不过我导入了一个接口,这就是为什么我在底部使用它)。因此,您的第一个选项无法工作-我在应用程序中的多个位置使用了
customFunction
,因此将
config
作为对象文本传递是不可行的。这就是为什么我要将其存储在变量中。关于您的第三个选项,我不知道如何在我的情况下应用它。@Cracko是什么让您对第三个选项感到困惑d选项?
config
参数必须是泛型类型参数,并且您需要一个额外的参数,该参数始终作为值true传递,但其类型将根据类型是否完全匹配而改变。如果匹配不完全,则类型将不为true,因此调用将导致错误,我现在明白了hat指定需要在
config
中包含
值的所有属性(而我希望它们是可选的)。此外,
错误的
属性仍然允许在
配置中
…或者也有可能我使用不正确,需要更多地使用它。@crazko否属性可以保留为可选,只是id
配置
有额外属性,您将得到一个错误。我添加了一个游乐场链接来演示该行为。The错误不会出现在
配置
参数上,而是出现在
验证
参数上