如何解决TypeScript中ESLint的'Type 'T[K]' is not assignable to type 'never''警告?
TypeScript类型错误:Type 'T[K]' is not assignable to type 'never' 解决思路
问题描述
代码功能正常,但以下两行触发ESLint类型警告:
item[key as keyof ICollectionMetaColumn] = value mapping[key as keyof ISynchronizationTargetMapping] = value
警告内容:
Type 'T[K]' is not assignable to type 'never'.
相关完整代码:
function setValue<T extends ICollectionMetaColumn | ISynchronizationTargetMapping, K extends keyof T>( index: number, key: K, value: T[K], ) { if (isICollectionMetaColumn(_metaColumns.value[index])) { const item = _metaColumns.value[index] as ICollectionMetaColumn // 此处触发警告 item[key as keyof ICollectionMetaColumn] = value emit('update:columns', unref(_metaColumns)) if (key === 'columnName' && !value && _metaColumns.value.length === 1) emit('update:columns', []) } else { const mapping = _metaColumns.value[index] as ISynchronizationTargetMapping // 此处触发警告 mapping[key as keyof ISynchronizationTargetMapping] = value emit('update:mapping', unref(_metaColumns)) if (key === 'destinationField' && !value && _metaColumns.value.length === 1) emit('update:mapping', []) } } function isICollectionMetaColumn(item: ICollectionMetaColumn | ISynchronizationTargetMapping) { return !('destinationField' in item) } const metaColumns = ref<(ICollectionMetaColumn | ISynchronizationTargetMapping)[]>() const _metaColumns = ref<(ICollectionMetaColumn | ISynchronizationTargetMapping)[]>(unref(metaColumns).length > 0 ? unref(metaColumns) : Array.isArray(unref(metaColumns)[0]) && isICollectionMetaColumn(unref(metaColumns)[0]) ? [{ columnName: '', type: 'varchar' }] as ICollectionMetaColumn[] : [{ destinationField: '', path: '' }] as ISynchronizationTargetMapping[], ) interface ICollectionMetaColumn { columnName: string type: 'bigint' | 'binary' | 'bit' | 'boolean' } interface ISynchronizationTargetMapping{ destinationField: string, path: string }
问题原因
泛型T是ICollectionMetaColumn | ISynchronizationTargetMapping的联合类型,K是T的键,但TypeScript无法将函数分支内的具体类型(比如ICollectionMetaColumn)和泛型参数T关联起来。当你将key断言为某一类型的键时,value的类型T[K]可能属于联合类型中的另一个分支,导致类型不兼容,最终被推导为never。
解决方法
方法1:使用函数重载替代泛型联合
重载可以明确不同参数组合对应的类型,消除类型歧义:
// 定义重载签名 function setValue(index: number, key: keyof ICollectionMetaColumn, value: ICollectionMetaColumn[keyof ICollectionMetaColumn]): void; function setValue(index: number, key: keyof ISynchronizationTargetMapping, value: ISynchronizationTargetMapping[keyof ISynchronizationTargetMapping]): void; // 实现函数 function setValue( index: number, key: keyof ICollectionMetaColumn | keyof ISynchronizationTargetMapping, value: any ) { const item = _metaColumns.value[index]; if (isICollectionMetaColumn(item)) { item[key as keyof ICollectionMetaColumn] = value as ICollectionMetaColumn[keyof ICollectionMetaColumn]; emit('update:columns', unref(_metaColumns)); if (key === 'columnName' && !value && _metaColumns.value.length === 1) emit('update:columns', []); } else { item[key as keyof ISynchronizationTargetMapping] = value as ISynchronizationTargetMapping[keyof ISynchronizationTargetMapping]; emit('update:mapping', unref(_metaColumns)); if (key === 'destinationField' && !value && _metaColumns.value.length === 1) emit('update:mapping', []); } }
方法2:在分支内明确断言value类型
如果不想改动函数结构,可以在赋值时同时断言value的类型,匹配当前分支的item类型:
// ICollectionMetaColumn分支 const item = _metaColumns.value[index] as ICollectionMetaColumn; item[key as keyof ICollectionMetaColumn] = value as ICollectionMetaColumn[keyof ICollectionMetaColumn]; // ISynchronizationTargetMapping分支 const mapping = _metaColumns.value[index] as ISynchronizationTargetMapping; mapping[key as keyof ISynchronizationTargetMapping] = value as ISynchronizationTargetMapping[keyof ISynchronizationTargetMapping];
方法3:优化泛型约束(更严谨的类型关联)
通过泛型约束让TypeScript明确T和分支类型的关联,不过需要调整函数逻辑:
function setValue<T extends ICollectionMetaColumn | ISynchronizationTargetMapping>( index: number, key: keyof T, value: T[keyof T], ) { const item = _metaColumns.value[index] as T; if ('columnName' in item) { (item as ICollectionMetaColumn)[key as keyof ICollectionMetaColumn] = value as ICollectionMetaColumn[keyof ICollectionMetaColumn]; emit('update:columns', unref(_metaColumns)); if (key === 'columnName' && !value && _metaColumns.value.length === 1) emit('update:columns', []); } else { (item as ISynchronizationTargetMapping)[key as keyof ISynchronizationTargetMapping] = value as ISynchronizationTargetMapping[keyof ISynchronizationTargetMapping]; emit('update:mapping', unref(_metaColumns)); if (key === 'destinationField' && !value && _metaColumns.value.length === 1) emit('update:mapping', []); } }
内容的提问来源于stack exchange,提问作者stewchicken
相关产品推荐
相关产品推荐

