Typescript: Coliziuni de nume de proprietăți în tipuri vs interfețe
Să zicem că am 2 tipuri cu același nume de proprietate, dar cu tipuri de date diferite:
type A = {
myProperty:string
}
type B = {
myProperty:number
}
Dacă extind ambele folosind o interfață, văd o eroare, așa cum mă așteptam:
interface C extends A, B {}
Interface 'C' cannot simultaneously extend types 'A' and 'B'.
Named property 'myProperty' of types 'A' and 'B' are not identical.
Dar dacă folosesc un tip pentru a extinde ambele, nu există nicio excepție. În acest caz, care este tipul de date rezultat al myProperty? Există o modalitate de a verifica tipul de date rezultat?
type C = A & B; // no error
Nu pot să stabilesc o valoare pentru myProperty (șir de caractere sau număr) dacă C este declarat ca un tip. Care este cea mai bună modalitate de a gestiona acest scenariu?
function F(myParameter:C) {
console.log(myParameter);
}
F({myProperty: 90});
(property) myProperty: never
Type 'number' is not assignable to type 'never'.ts(2322)
index.ts(3, 3): The expected type comes from property 'myProperty' which is declared here on type 'C'
Aceeași eroare dacă apelez funcția ca F({myProperty: 'test data'});.
Loc de joacă: https://codesandbox.io/s/typescript-playground-export-forked-dglbq5?file=/index.ts
Răspuns #1
Dacă doriți să intersectați două tipuri conflictuale, dar totuși doriți să instanțiați tipul rezultat, există mai multe opțiuni pentru a le gestiona. Notă că ambele soluții nu vor rezolva conflictele pentru proprietățile înzăpezite mai adânc decât primul nivel.
Să presupunem că avem două interfețe A și B pe care vrem să le intersectăm.
interface A {
a: string
b: string
}
interface B {
a: number
c: string
}
Prima opțiune ar putea fi să se omită proprietatea conflictuală din tipul rezultat.
type IntersectByOmitting<A, B> = {
[K in keyof (A & B) as K extends keyof A & keyof B
? [A[K] & B[K]] extends [never]
? never
: K
: K
]: K extends keyof A ? A[K] : B[K & keyof B]
}
type T0 = IntersectByOmitting<A, B>
// ^? type T0 = { b: string; c: string; }
Deoarece a se rezolvă la never în intersecție, va fi omis din tipul rezultat.
Așa cum ai spus în comentariu, s-ar putea să vrei să ai în schimb o uniune a proprietăților conflictuale.
type IntersectByUnion<A, B> = {
[K in keyof (A & B)]: K extends (keyof A & keyof B) ?
[A[K] & B[K]] extends [never]
? A[K] | B[K]
: A[K] & B[K]
: K extends keyof A ? A[K] : B[K & keyof B]
}
type T1 = IntersectByUnion<A, B>
// type T1 = {
// a: string | number;
// b: string;
// c: string;
// }
Tipul lui a este acum string | number.
Teren de joacă
