一个困扰我许久的TypeScript定义问题
点击关注公众号,“技术干货”及时达!
最近在使用TypeScript定义函数参数时,我遇到了一个难题,这让我感到困扰。我猜想这可能是因为我对TypeScript的掌握不够深入。虽然我问了无数次ChatGPT,但未能获得满意的解答。至今还没解决方案。今天我将这个问题分享出来,希望能听到大家的意见,看看是否有解决方案。
我在定义addComp函数时,设置了一个参数,该参数是一个数组。数组的每一项包含两个属性:type表示组件的类型,props包括组件的可配置属性。不同组件的props有共同的也有独特的属性,例如:
[
{
type:'Input',
props:{
required:true,
defaultValue:'默认值',
placeholder:'请输入',
},
},
{
type:'Select',
props:{
required:true,
defaultValue:['1'],
placeholder:'请输入',
options:[
{
label:'选项一',
value:'1'
}
]
},
},
]
我对以上数据做了如下的TypeScript。
//定义props属性的基础接口
interfaceCompProps{
required?:boolean;
placeholder?:string;
}
//定义特定控件类型的props接口
interfaceInputPropsextendsCompProps{
defaultValue?:string;
}
interfaceSelectPropsextendsCompProps{
defaultValue?:string[]|number[];
options:Array{label:string,value:string}
}
typeCompPropsMap={
Input:InputProps;
Select:SelectProps;
};
//定义组件类型的联合类型
typeCompType='Input'|'Select';
//定义AddCompParam中每一项的接口
interfaceAddCompParamTextendsCompType{
type:
props:CompPropsMap[T];
}
然而,在使用过程中发现了问题。例如,以下示例应该报错,但实际上并没有:
//示例对象
constaddCompParam:AddCompParamCompType[]=
[
{
type:'Input',
props:{
required:true,
defaultValue:['默认值'],//这里应为string,错误地使用了string[]
placeholder:'请输入',
options:[],//这是一个无关属性,不应存在于InputProps中
},
},
];
按理论来推动,此时应该会报错,但是实际不会报错。我尝试开启严格模式,重启TypeScript服务,还是不会报错。问 ChatGPT,得到的答复是
?在您的例子中,AddCompParam的定义是基于泛型的,因此 TypeScript 会根据传入的类型进行推断。由于CompPropsMap中的InputProps和SelectProps是通过继承和映射来定义的,TypeScript 可能没有对props的结构进行严格的检查。具体来说,props是一个对象,TypeScript 在类型检查时可能会允许额外的属性存在于对象中,只要对象中包含了所需的属性。这就是为什么在Input的props中添加了options属性,TypeScript 仍然不会报错。
?我对上面的答复不是很满意。为了让TypeScript 能够报错,我换了一种定义方式
//定义props属性的基础接口
interfaceCompProps{
required?:boolean;
placeholder?:string;
}
//定义特定控件类型的props接口
interfaceInputPropsextendsCompProps{
defaultValue?:string;
}
interfaceSelectPropsextendsCompProps{
defaultValue?:string[]|number[];
options:Array{label:string,value:string}
}
//定义AddCompParam中每一项的接口
typeAddCompParam=
{type:'Input';props:InputProps}|
{type:'Select';props:SelectProps
然而,在实际使用过程中,我发现了另一个严重的问题:错误信息的提示并不准确。
//示例对象
constaddCompParam:AddCompParam[]=
[
{
type:'Input',
props:{
required:true,
defaultValue:['1'],
placeholder:'请输入',
},
},
];
报错信息如下所示:
?不能将类型{ required: true; defaultValue: string[]; placeholder: string; }分配给类型InputProps | SelectProps。
类型 { required: true; defaultValue: string[]; placeholder: string; } 中缺少属性 options,但类型 SelectProps 中需要该属性。
?这个错误提示令我困惑。虽然我明确将type设置为Input,问题显然出在props的defaultValue类型上,但错误提示却显示缺少options属性。尽管我尝试补全了这个属性,错误提示改变了,但仍未指向defaultValue的类型问题。
//示例对象
constaddCompParam:AddCompParam[]=
[
{
type:'Input',
props:{
required:true,
defaultValue:['1'],
placeholder:'请输入',
options:[]
},
},
];
报错信息如下所示:
?不能将类型{ type: "Input"; props: { required: true; placeholder: string; defaultValue: string[]; options: { label: string; value: string; }[]; }; }分配给类型AddCompParam。
属性props的类型不兼容。
对象字面量只能指定已知属性,并且options不在类型InputProps中。
?我再次询问 ChatGPT 得到的答复是
?您遇到的错误提示是由于 TypeScript 处理联合类型时的类型推断机制。在您的代码中,AddCompParam是一个联合类型,它可以是Input或Select类型。当 TypeScript 检查addCompParam数组中的对象时,它会尝试确保props属性符合InputProps或SelectProps的定义。
??在您的示例中,您定义了一个Input类型的对象,但是在props中,您传递了一个defaultValue的值为['1'],这是一个字符串数组(string[]),而InputProps中的defaultValue应该是一个字符串(string)。因此,TypeScript 在尝试推断props的类型时,发现defaultValue的类型不匹配。
??由于props的类型是InputProps | SelectProps,TypeScript 会将props视为可能是SelectProps类型,因此它会检查SelectProps的所有必需属性,包括options。这就是为什么您会看到提示缺少options属性。
?目前我还不确定如何解决这个问题。如果按照下面的方式定义:
typeAddCompParam=[
{type:'Input';props:InputProps},
{type:'Select';props:SelectProps}
];
这种定义方式似乎限制了addCompParam参数中每个项的固定位置,例如type: 'Select'必须位于addCompParam数组的第二个位置。这并不是我想要的效果。
我尝试了多种方式向ChatGPT描述这个问题,但是得到的回答都未能提供正确的解决方案。可能是我的问题描述不够清晰,导致ChatGPT无法完全理解问题的核心。
如果各位掘友有遇到过类似问题并找到了解决方案,恳请在评论区分享一下,非常感谢!
掘友 鱼骨头jinx 的解决方案,感谢提供。
?如果把type 挪到 props中,报错信息是对的,感觉是层级的问题,ts没有吧type和props结合起来一起判断类型,而是单独判断。
?//定义props属性的基础接口
interfaceCompPropsTextendsCompType{
type://将type字段作为泛型参数
required?:boolean;
placeholder?:string;
}
//定义特定控件类型的props接口
interfaceInputPropsextendsCompProps'Input'{
defaultValue?:string;
}
interfaceSelectPropsextendsCompProps'Select'{
defaultValue?:string[]|number[];
options:Array{label:string,value:string}
}
typeCompPropsMap={
Input:InputProps;
Select:SelectProps;
};
//定义组件类型的联合类型
exporttypeCompType='Input'|'Select';
//定义AddCompParam中每一项的接口
interfaceAddCompParamTextendsCompType{
type:
props:CompPropsMap[T];
}
exportdefaultAddCompParam;
//示例对象
constaddCompParam:AddCompParam[]=
[
{
type:'Input',
props:{
type:'Input',
required:true,
placeholder:'请输入',
defaultValue:['1'],
},
},
{
type:'Select',
props:{
type:'Select',
required:true,
placeholder:'请输入',
defaultValue:['1'],
options:[],
},
},
掘友 用户4512308223327 的解决方案,感谢提供。
//定义props属性的基础接口
interfaceCompPropsTextendsCompType{
type://将type字段作为泛型参数
required?:boolean;
placeholder?:string;
}
//定义特定控件类型的props接口
interfaceInputPropsextendsCompProps'Input'{
defaultValue?:string;
}
interfaceSelectPropsextendsCompProps'Select'{
defaultValue?:string[]|number[];
options:Array{label:string,value:string}
}
typeCompPropsMap={
Input:InputProps;
Select:SelectProps;
};
//定义组件类型的联合类型
exporttypeCompType=keyofCompPropsMap;
typeAddCompParam={
[keyinCompType]:{
type:key;
props:CompPropsMap[key]
}
}[CompType]
//示例对象
constaddCompParam:AddCompParam[]=
[
{
type:'Input',
props:{
type:'Input',
required:true,
placeholder:'请输入',
defaultValue:['1'],
},
},
{
type:'Select',
props:{
type:'Select',
required:true,
placeholder:'请输入',
defaultValue:['1'],
options:[],
},
},
掘友 何缘小夏 的解决方案,感谢提供。
//定义props属性的基础接口
interfaceCompProps{
required?:boolean;
placeholder?:string;
}
//定义特定控件类型的props接口
interfaceInputPropsextendsCompProps{
defaultValue?:string;
}
interfaceSelectPropsextendsCompProps{
defaultValue?:string[]|number[];
options:Array{label:string;value:string}
}
typeCompPropsMap={
Input:InputProps;
Select:SelectProps;
};
//定义组件类型的联合类型
typeCompType='Input'|'Select';
//定义AddCompParam中每一项的接口
interfaceAddCompParamTextendsCompType{
type:
props:CompPropsMap[T];
}
functionaddCompTextendsCompType(param:AddCompParam){
returnparam;
}
addComp({
type:'Select',
props:{
required:true,
defaultValue:[8],//这里应为string,错误地使用了string[]
placeholder:'请输入',
//这是一个无关属性,不应存在于InputProps中
options:[]
}
});
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线