如何在不获取 "could be instantiated with a different subtype of constraint" 的情况下为联合类型参数提供默认值
How to provide default value for union type parameter without getting "could be instantiated with a different subtype of constraint"
作为 ...
的后续行动
有没有办法在下面的例子中为 valueProp
提供默认值?
type ValueType = 'value' | 'defaultValue'
type Props<T extends ValueType> =
Record<T, string>
& { other: string }
function props<T extends ValueType>(valueProp: T): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
let { defaultValue, other } = props('defaultValue') // ok
let { value } = props('value') // ok
当我尝试这个时:
function props<T extends ValueType>(valueProp: T = 'value'): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
,我得到这个错误:
Type '"value"' is not assignable to type 'T'.
'"value"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ValueType'.
我大体上理解这个错误 (1, 2, 3, 4),但仍然不知道解决这个错误的最佳方法。
有没有一种简单的方法可以完成我想做的事情?
似乎应该有一种简单的方法来提供默认值,但也许默认值不能很好地与通用类型约束混合?
泛型类型的默认类型?
我试过这个:
function props<T extends ValueType = 'value'>(valueProp: T = 'value'): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
但当然得到了同样的错误,因为如果提供了特定的 T
,T 仍然可以是 defaultValue
:
props<'defaultValue'>()
类型断言?
我想过这样做,编译通过,但仍然不能阻止 valueProp
不同意 T:
function props<T extends ValueType>(valueProp: T = 'value' as T): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
console.log(props<'defaultValue'>())
// => {value: "value", other: "other"}
更复杂的东西?
我仍然希望有一个简单的解决方案,但如果没有,也许可以使用更复杂的方法?
也许使用从 type 映射到该类型的默认 value 的映射 table?
对于灵感,也许是这样的:
根据 Titian Cernicova-Dragomir 的评论,我们可以使用函数重载非常简单地做到这一点:
type ValueType = 'value' | 'defaultValue'
type Props<T extends ValueType> =
Record<T, string>
& { other: string }
function props<T extends ValueType>(valueProp: T): Props<T>
function props(): Props<'value'>
function props(valueProp: ValueType | undefined = 'value') {
return {
[valueProp]: 'value',
other: 'other',
}
}
或者如果我们想将 valueProp
从位置参数移动到伪命名参数(使用对象解构):
type PropsOptions<VT extends ValueType | undefined> = {
valueProp?: VT
}
function props<VT extends ValueType>({valueProp}: PropsOptions<VT>): Props<VT>
function props(): Props<'value'>
function props({ valueProp = 'value' }: PropsOptions<ValueType | undefined> = {}) {
return {
[valueProp]: 'value',
other: 'other',
}
}
作为
有没有办法在下面的例子中为 valueProp
提供默认值?
type ValueType = 'value' | 'defaultValue'
type Props<T extends ValueType> =
Record<T, string>
& { other: string }
function props<T extends ValueType>(valueProp: T): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
let { defaultValue, other } = props('defaultValue') // ok
let { value } = props('value') // ok
当我尝试这个时:
function props<T extends ValueType>(valueProp: T = 'value'): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
,我得到这个错误:
Type '"value"' is not assignable to type 'T'.
'"value"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'ValueType'.
我大体上理解这个错误 (1, 2, 3, 4),但仍然不知道解决这个错误的最佳方法。
有没有一种简单的方法可以完成我想做的事情?
似乎应该有一种简单的方法来提供默认值,但也许默认值不能很好地与通用类型约束混合?
泛型类型的默认类型?
我试过这个:
function props<T extends ValueType = 'value'>(valueProp: T = 'value'): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
但当然得到了同样的错误,因为如果提供了特定的 T
,T 仍然可以是 defaultValue
:
props<'defaultValue'>()
类型断言?
我想过这样做,编译通过,但仍然不能阻止 valueProp
不同意 T:
function props<T extends ValueType>(valueProp: T = 'value' as T): Props<T> {
return {
[valueProp]: 'value',
other: 'other',
} as Props<T>
}
console.log(props<'defaultValue'>())
// => {value: "value", other: "other"}
更复杂的东西?
我仍然希望有一个简单的解决方案,但如果没有,也许可以使用更复杂的方法?
也许使用从 type 映射到该类型的默认 value 的映射 table?
对于灵感,也许是这样的:
根据 Titian Cernicova-Dragomir 的评论,我们可以使用函数重载非常简单地做到这一点:
type ValueType = 'value' | 'defaultValue'
type Props<T extends ValueType> =
Record<T, string>
& { other: string }
function props<T extends ValueType>(valueProp: T): Props<T>
function props(): Props<'value'>
function props(valueProp: ValueType | undefined = 'value') {
return {
[valueProp]: 'value',
other: 'other',
}
}
或者如果我们想将 valueProp
从位置参数移动到伪命名参数(使用对象解构):
type PropsOptions<VT extends ValueType | undefined> = {
valueProp?: VT
}
function props<VT extends ValueType>({valueProp}: PropsOptions<VT>): Props<VT>
function props(): Props<'value'>
function props({ valueProp = 'value' }: PropsOptions<ValueType | undefined> = {}) {
return {
[valueProp]: 'value',
other: 'other',
}
}