Excluir propiedad del tipo


158

Me gustaría excluir una sola propiedad del tipo. ¿Cómo puedo hacer eso?

Por ejemplo tengo

interface XYZ {
  x: number;
  y: number;
  z: number;
}

Y quiero excluir la propiedad zpara obtener

type XY = { x: number, y: number };

Respuestas:


335

Para versiones de TypeScript de 3.5 o superior

En TypeScript 3.5, el Omittipo se agregó a la biblioteca estándar. Vea los ejemplos a continuación para saber cómo usarlo.

Para versiones de TypeScript inferiores a 3.5

En TypeScript 2.8, el Excludetipo se agregó a la biblioteca estándar, lo que permite escribir un tipo de omisión simplemente como:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

Para versiones de TypeScript inferiores a 2.8

No puede usar el Excludetipo en las versiones inferiores a 2.8, pero puede crear un reemplazo para usar el mismo tipo de definición que el anterior. Sin embargo, este reemplazo solo funcionará para los tipos de cadena, por lo que no es tan poderoso como Exclude.

// Functionally the same as Exclude, but for strings only.
type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>

Y un ejemplo de ese tipo en uso:

interface Test {
    a: string;
    b: number;
    c: boolean;
}

// Omit a single property:
type OmitA = Omit<Test, "a">; // Equivalent to: {b: number, c: boolean}

// Or, to omit multiple properties:
type OmitAB = Omit<Test, "a"|"b">; // Equivalent to: {c: boolean}

¡Excelente! Está declarando Diff<T, U>(con Ty Ucomo tipos disponibles para claves) como un Tsubconjunto con clave de una intersección de 3 tipos: escriba con clave igual que un valor para T, escriba con neverfor Uy escriba con neverpara todas las claves. Luego lo pasa a través del indexador para obtener los tipos de valores correctos. Estoy en lo cierto?
— Qwertiy

55
¡Sí! Pero esto tiene un inconveniente. Por ejemplo, Omit<{a?: string, b?: boolean}, "b">da como resultado {a: string | undefined}, que todavía acepta undefinedcomo valor, pero pierde el modificador opcional en a. :(
— CRice

Eso es triste ... Interesante de esa manera con declarar y difundir mantiene el modificador opcional ... ¿Hay alguna otra forma de mantenerlo?
— Qwertiy

1
@Qwertiy ¡Funciona! ¡Muchas gracias! Edité la publicación. Pero me pregunto cuál fue la diferencia, ya que lo que había allí era literalmente idéntico a la definición de tipo por Picklo que puedo ver.
— CRice el

3
Tenga en cuenta que para TS 3.5, la definición de biblioteca estándar de Omitdifiere de la dada aquí. En stdlib, es type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;El cambio, aunque leve, ha provocado cierto debate , así que tenga en cuenta la diferencia.
— CRice

41

Con el mecanografiado 2.8, puede usar el nuevo tipo incorporado Exclude. Las notas de la versión 2.8 en realidad mencionan esto en la sección "Tipos condicionales predefinidos":

Nota: El tipo Excluir es una implementación adecuada del tipo Diff sugerido aquí. [...] No incluimos el tipo Omitir porque está escrito trivialmente como Pick<T, Exclude<keyof T, K>>.

Aplicando esto a su ejemplo, el tipo XY podría definirse como:

type XY = Pick<XYZ, Exclude<keyof XYZ, "z">>

19

He encontrado solución declarando algunas variables y usando el operador de propagación para inferir el tipo:

interface XYZ {
  x: number;
  y: number;
  z: number;
}

declare var { z, ...xy }: XYZ;

type XY = typeof xy; // { x: number; y: number; }

Funciona, pero me alegraría ver una solución mejor.


3
Esta es una gran solución pre-2.8. typeofes una de las características menos apreciadas del mecanografiado.
— Jason Hoetger

1
¡Listo, me gusta :)! (para pre 2.8)
— maxime1992 01 de

Cómo puedo agregar z con tipo cadena en su resultado
— user602291

@ user602291, type Smth = XY & { z: string };?
— Qwertiy

1
Este es perfecto para la versión antigua del mecanografiado. No pude obtener la respuesta correcta para trabajar en 2.3, pero esta funcionó muy bien.
— k0pernikus

6

Si prefiere usar una biblioteca, use ts-essentials .

import { Omit } from "ts-essentials";

type ComplexObject = {
  simple: number;
  nested: {
    a: string;
    array: [{ bar: number }];
  };
};

type SimplifiedComplexObject = Omit<ComplexObject, "nested">;

// Result:
// {
//  simple: number
// }

// if you want to Omit multiple properties just use union type:
type SimplifiedComplexObject = Omit<ComplexObject, "nested" | "simple">;

// Result:
// { } (empty type)

PD: Encontrarás muchas otras cosas útiles allí;)



4

En Typecript 3.5+ :

interface TypographyProps {
    variant: string
    fontSize: number
}

type TypographyPropsMinusVariant = Omit<TypographyProps, "variant">

0

Me gusta eso:

interface XYZ {
  x: number;
  y: number;
  z: number;
}
const a:XYZ = {x:1, y:2, z:3};
const { x, y, ...last } = a;
const { z, ...firstTwo} = a;
console.log(firstTwo, last);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.