Tengo la función onMessage que obtiene eventos del SDK de un tercero en mi aplicación
interface TypeA { a:string, b:undefined } interface TypeB{ b: 'a'|'b', c: 'a'|'b' } type TypeC = TypeA | TypeB const onMassege=( event: TypeC )=>{ if (event.a === 'a'){ /* TS-ERROR Property 'a' does not exist on type 'TypeC' .Property 'a' does not exist on type 'TypeB */ } if ( event.b === 'a'){// good } } en el ejemplo anterior, el acceso a las propiedades event.a obtiene un error de type-script pero event.b no obtiene ningún error porque las propiedades b se definen en todos los tipos de interfaz TypeC
Necesito un tipo genérico para agregar propiedades faltantes en todos los tipos y agregar c: undefined a mi interfaz TypeC
Puede crear el tipo que está buscando definiendo un KeyUnion de tipo genérico que devuelve las claves de los objetos en una unión:
type KeyUnion<T> = T extends unknown ? keyof T : never y use esto para crear un tipo de objeto que tenga una propiedad para cada una de esas claves con como tipo de valor la unión de tipos posibles que la propiedad puede tener en los objetos en la unión, o undefined :
type Merge<T> = { [K in KeyUnion<T>]: T extends Record<K,any> ? T[K] | undefined : never } Ahora Merge<TypeC> se evaluará como
{ a: string | undefined; b: "a" | "b" | undefined; c: "a" | "b" | undefined } y puede hacer una verificación de tipo onMessage usando event: Merge<TypeC> .
Una desventaja de este enfoque es que pierde la seguridad de tipo en las cláusulas luego, ya que el event siempre tendrá el tipo Merge<TypeC> , por lo que incluso en el primer caso, el event seguirá teniendo una propiedad c , y en el segundo caso tendrá un a . Por esta razón, podría ser más seguro simplemente agregar un control adicional in la condición cuando sea necesario, de modo que el tipo de event se reduzca adecuadamente en cada caso:
const onMessage = (event: TypeC) => { if ('a' in event && event.a ==='a') { // event has type `TypeA` here } if (event.b ==='a') { // event has type `TypeB` here } }