typescript - 如何為聯合類型參數提供默認值而不出現「可能以約束的不同子類型實例化」的錯誤
作為我先前問題的後續...
在以下範例中,有沒有辦法為 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"}
更複雜一點的東西嗎?
我仍然希望有一個簡單的解決方法,但如果沒有,也許更複雜的方案會有效?
也許可以使用一個映射表,將 類型 對應到該類型的預設 值?
作為靈感,也許像這樣的東西:
‘CustomEnum.Case’ 可分配給型別 ‘T’ 的約束,但 ‘T’ 可能會使用約束 ‘CustomEnum’ 的不同子型別來實例化
https://github.com/microsoft/TypeScript/issues/29528#issuecomment-456804257 ?
答案#1
根據 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',
}
}
播放
