英文:
typescript: Why does my default generic type results the determination that the param could be of that type only?
问题
抱歉,我无法直接运行代码或提供与代码相关的输出。
英文:
I tried to use a generic type with a default value
and use inference based on it to determine other function arguments,
but it seems to determine that the default type is the only type allowed for that argument,
is that supposed to happen?
am i doing something wrong?
this is the code snippet:
type MyComponentOption = HasNameId | HasLabelValue
type HasLabelValue = { label: string, value: number }
type HasNameId = { name: string, id: number }
interface MyComponentProp<
OptL extends ('label' | 'name') = 'label',
OptV = OptL extends 'label' ? 'value' : 'id',
Multiple extends boolean = false,
S = OptL extends 'label' ? HasLabelValue : HasNameId,
> {
optionLabel?: OptL;
optionValue?: OptV;
multiple?: Multiple,
preSelected?: Multiple extends true ? S[] : S;
}
export const MyCOmponent = (prop: MyComponentProp) => {
const {
optionLabel,
optionValue,
multiple,
preSelected,
} = prop
// v const preSelected: HasLabelValue | undefined
if (preSelected == null) console.log('no preselected options')
else {
if (isOfLabelValue(preSelected)) {
console.log(preSelected.label)
} else {
console.log(preSelected.name) // Error : Property 'name' does not exist on type 'never'
}
}
}
function isOfLabelValue(opt: MyComponentOption): opt is HasLabelValue {
return ('label' in opt && 'value' in opt)
}
答案1
得分: 1
您的界面是通用的,但您的函数组件不是,因此通用类型默认为它们的默认类型。因此,您需要使函数成为通用的。
但现在您需要处理preSelected
是数组的情况,这仍然会导致错误。
英文:
Your interface is generic but your function component is not, so the generic types default to their default types. So, you need to make the function generic
type MyComponentOption = HasNameId | HasLabelValue
type HasLabelValue = { label: string, value: number }
type HasNameId = { name: string, id: number }
interface MyComponentProp<
OptL extends ('label' | 'name') = 'label',
OptV = OptL extends 'label' ? 'value' : 'id',
Multiple extends boolean = false,
// S needs to extend MyComponentOption, you assign default values but users of this interface can type anything in there if you don't extend
S extends MyComponentOption = OptL extends 'label' ? HasLabelValue : HasNameId,
> {
optionLabel?: OptL;
optionValue?: OptV;
multiple?: Multiple,
preSelected?: Multiple extends true ? S[] : S;
}
export const MyCOmponent = <
OptL extends ('label' | 'name') = 'label',
OptV = OptL extends 'label' ? 'value' : 'id',
Multiple extends boolean = false,
S extends MyComponentOption = OptL extends 'label' ? HasLabelValue : HasNameId,
>(prop: MyComponentProp<OptL, OptV, Multiple, S>) => {
const {
optionLabel,
optionValue,
multiple,
preSelected,
} = prop
// v const preSelected: HasLabelValue | undefined
if (preSelected == null) console.log('no preselected options')
else {
if (isOfLabelValue(preSelected)) {
console.log(preSelected.label)
} else {
console.log(preSelected.name)
}
}
}
function isOfLabelValue(opt: MyComponentOption | MyComponentOption[]): opt is HasLabelValue {
return ('label' in opt && 'value' in opt)
}
But now you need to handle cases where preSelected
is an array, so this will still error.
答案2
得分: 0
看起来问题在于preSelected类型没有被正确地推断。
您可以通过在函数签名中为preSelected提供显式类型或使用multiple属性的类型推断来修复这个问题:
export const MyComponent = (prop: MyComponentProp) => {
const {
optionLabel,
optionValue,
multiple,
preSelected,
} = prop
const preSelectedType = multiple ?
(prop.preSelected as MyComponentOption[])[0].label ? HasLabelValue : HasNameId :
(prop.optionLabel === 'label' ? HasLabelValue : HasNameId);
if (preSelected == null) console.log('没有预选选项')
else {
if (isOfLabelValue(preSelected as preSelectedType)) {
console.log((preSelected as preSelectedType).label)
} else {
console.log((preSelected as preSelectedType).name)
}
}
}
英文:
It seems that the problem is that the preSelected type is not being inferred correctly.
You can fix this by providing an explicit type for preSelected in the function signature or using type inference based on the multiple property:
export const MyCOmponent = (prop: MyComponentProp) => {
const {
optionLabel,
optionValue,
multiple,
preSelected,
} = prop
const preSelectedType = multiple ?
(prop.preSelected as MyComponentOption[])[0].label ? HasLabelValue : HasNameId :
(prop.optionLabel === 'label' ? HasLabelValue : HasNameId);
if (preSelected == null) console.log('no preselected options')
else {
if (isOfLabelValue(preSelected as preSelectedType)) {
console.log((preSelected as preSelectedType).label)
} else {
console.log((preSelected as preSelectedType).name)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论