typescript - Ako nastaviť predvolené argumenty generickej funkcie s priesečnými typmi
Snažím sa zistiť, prečo nasledujúci kód nebude fungovať tak, ako očakávam. Zdá sa, že typ prieniku funguje správne (keď je znova definovaný vo vnútri funkcie), avšak použitie ako predvoleného typu generického argumentu nie.
interface A {
a: string
}
interface B {
b: string
}
interface C {
c: string
}
function returnStuff<T = A & B>(
optionalReturnFn?: (value: T) => T): (value: T) => T {
const defaultReturnFn = (value: T) => {
value.a // <----- why does this a error
return value
}
return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}
function returnStuff2<T extends A & B>(
optionalReturnFn?: (value: T) => T): (value: T) => T {
const defaultReturnFn = (value: T) => {
value.a // <----- while this one does not
return value
}
return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}
const bc: B & C = { b: 'b', c: 'c' } // <--- valid intersection type
// Works as expected when calling fn but DOESN't work as I'd expect internally to fn
returnStuff<B & C>((value) => {
return value
})
// Doesn't work when calling fn but DOES work as expected internally to fn
returnStuff2<B & C>((value) => {
return value
})
Tu je TS Playground, ak si chcete pohrať s chybami.
AKTUALIZÁCIA: Nakoniec som pridal ochranu typu a použil ju v definícii funkcie returnStuff.
...
function isDefaultType<DefaultType>(
record: any,
keys: string[]
): record is DefaultType {
return every(keys, (key) => key in record)
}
function returnStuff<T = A & B>(
optionalReturnFn?: (value: T) => T): (value: T) => T {
const defaultReturnFn = (value: T) => {
if(isDefaultType<T>(value, ['a', 'b']) {
value.a // <----- no longer throws an error
return value
}
}
return optionalReturnFn ? optionalReturnFn : defaultReturnFn
}
Odpoveď č. 1
vrátiťVeci
T=A & B zobrazuje chybu vedľa value.a, pretože ste nastavili len predvolenú hodnotu, ale neobmedzili ste typy T pomocou extends, T teda môže byť stále čokoľvek, ale ak nebol špecifikovaný, bola by to A & B. returnStuff<C>(v => v); - funguje. returnStuff(v => v); - tiež funguje. value.a zlyháva, pretože value môže byť čokoľvek, string, undefined atď.
správny spôsob by bol T extends A & B=A & B
returnStuff2
returnStuff2<B & C> nefunguje, pretože T extends A & B (nie predvolená hodnota, ale definovaný základný typ) vyžaduje vlastnosť a, ktorá chýba v unii B a C.