TypeScript函数参数为多对象联合类型时属性不存在报错如何解决
问题根因
- 联合类型仅允许直接访问所有类型成员共有的属性,你在函数入参位置直接解构
checked/options/placeholder这类仅部分类型拥有的属性,TS会直接抛错。 - 入参联合类型错误加入了
TPSelectFieldOption,该类型是下拉选项的结构,不属于输入字段类型,本身缺少name/type等输入项公共属性,进一步放大了类型不兼容问题。 - 提前解构属性的写法破坏了TS的类型收窄逻辑:TS的可辨识联合类型收窄是基于完整对象做判断的,把属性拆成独立变量后,
switch(type)的判断无法关联到已经解构出来的其他属性,就算类型定义正确也无法识别。 - 所有字段接口的
type属性被定义为通用string类型,TS无法通过type的具体值匹配到对应的字段接口,类型收窄完全不生效。
修复方案
第一步:给各字段接口的type属性绑定固定字面量值
让TS可以通过type的取值识别对应字段类型:
interface TPField { // CRM id as a hash. id: string name: string label: string readonly: boolean disabled: boolean value: string type: string } /** * Interface for base field with text field. */ export interface TPTextField extends TPField { type: 'text' autocomplete: boolean autofocus: boolean placeholder: string required: boolean maxlength: number } /** * Interface for input type number field. */ export interface TPNumberField extends TPTextField { type: 'number' min: { enabled: boolean value: number } max: { enabled: boolean value: number } step: number } /** * Interface for input type checkbox field. */ export interface TPCheckboxField extends TPField { type: 'checkbox' checked: boolean } export interface TPRadioField extends TPField { type: 'radio' checked: boolean } /** * Interface for select field. */ export interface TPSelectField extends TPField { type: 'select' multiple: boolean options: TPSelectFieldOption[] } /** * Interface for a single option for select field. */ export interface TPSelectFieldOption { disabled: boolean label: string value: string }
第二步:修正函数入参与实现逻辑
移除不属于输入字段的TPSelectFieldOption类型,不要提前解构参数,在switch块完成类型收窄后再访问对应属性:
// 定义输入字段联合类型,仅保留合法的输入项类型 type TPInputField = TPCheckboxField | TPNumberField | TPSelectField | TPTextField | TPRadioField const renderInput = (field: TPInputField) => { switch (field.type) { case 'text': return ( <StyledFormItem name={field.name}> {/* 类型收窄为TPTextField,可正常访问placeholder */} <Input defaultValue={field.value} type='text' placeholder={field.placeholder} /> </StyledFormItem> ) case 'number': return ( <StyledFormItem name={field.name}> {/* 类型收窄为TPNumberField,可正常访问min/max/step等属性 */} <Input defaultValue={field.value} type='number' /> </StyledFormItem> ) case 'checkbox': return ( <StyledFormItem name={field.name} valuePropName='checked'> {/* 类型收窄为TPCheckboxField,可正常访问checked */} <Checkbox checked={field.checked}>{field.label}</Checkbox> </StyledFormItem> ) case 'select': return ( <StyledFormItem name={field.name}> {/* 类型收窄为TPSelectField,可正常访问options */} <Select options={field.options} /> </StyledFormItem> ) case 'radio': return ( <StyledFormItem name={field.name} valuePropName='checked'> <Radio checked={field.checked}>{field.label}</Radio> </StyledFormItem> ) } }
不要用
Record<string, unknown>绕开类型检查,这种写法会丢失所有类型提示,完全放弃TS的类型校验能力。
内容的提问来源于stack exchange,提问作者kkkkkkkkkkkkkkkkk
相关产品推荐
相关产品推荐

