Excluir propriedade do tipo

157

Gostaria de excluir uma única propriedade do tipo. Como eu posso fazer isso?

Por exemplo eu tenho

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

E eu quero excluir propriedades zpara obter

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

Respostas:

334

Para versões do TypeScript iguais ou superiores a 3,5

No TypeScript 3.5, o Omittipo foi adicionado à biblioteca padrão. Veja exemplos abaixo para saber como usá-lo.

Para versões do TypeScript abaixo de 3,5

No TypeScript 2.8, o Excludetipo foi adicionado à biblioteca padrão, o que permite que um tipo de omissão seja escrito simplesmente como:

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

Para versões do TypeScript abaixo de 2,8

Você não pode usar o Excludetipo nas versões abaixo de 2.8, mas pode criar um substituto para ele para usar o mesmo tipo de definição acima. No entanto, essa substituição funcionará apenas para tipos de string, portanto, não é tão poderosa quanto 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>>

E um exemplo desse tipo em 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}
CRice
fonte
Ótimo! Você está declarando Diff<T, U>(com Te Ucomo tipos disponíveis para chaves) como um Tsubconjunto com uma chave de uma interseção de 3 tipos: digite com a chave igual a um valor para T, digite com neverpara Ue digite com neverpara todas as chaves. Em seguida, você o passa pelo indexador para obter os tipos de valores corretos. Estou certo?
Qwertiy
5
Sim! Mas isso tem uma desvantagem. Por exemplo, Omit<{a?: string, b?: boolean}, "b">resulta em {a: string | undefined}, que ainda aceita undefinedcomo valor, mas perde o modificador opcional ativado a. :(
CRice
Isso é triste .. Interessante assim com declarar e espalhar mantém o modificador opcional ... Existe alguma outra maneira de mantê-lo?
precisa saber é o seguinte
1
@Qwertiy It works! Muito Obrigado! Eu editei a postagem. Mas eu me pergunto qual seria a diferença, já que o que havia lá era literalmente idêntico à definição de tipo Pick, tanto quanto eu posso ver.
CRice
3
Observe que, para o TS 3.5, a definição de biblioteca padrão Omitdifere da apresentada aqui. No stdlib, é type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;A mudança, embora leve, causou algum debate , portanto, esteja ciente da diferença.
CRice 20/05/19
41

Com o texto datilografado 2.8, você pode usar o novo Excludetipo interno. As notas de versão 2.8 mencionam isso na seção "Tipos condicionais predefinidos":

Nota: O tipo Excluir é uma implementação adequada do tipo Diff sugerido aqui. [...] não incluímos o tipo Omit, porque ele é escrito trivialmente como Pick<T, Exclude<keyof T, K>>.

Aplicando isso ao seu exemplo, o tipo XY pode ser definido como:

type XY = Pick<XYZ, Exclude<keyof XYZ, "z">>
Jason Hoetger
fonte
19

Eu encontrei uma solução ao declarar algumas variáveis ​​e usando o operador spread para inferir o tipo:

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

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

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

Funciona, mas ficaria feliz em ver uma solução melhor.

Qwertiy
fonte
3
Esta é uma ótima solução pré-2,8. typeofé um dos recursos menos apreciados do texto datilografado.
21419 Jason Hoetger
1
Inteligente, eu gosto :)! (for pre 2.8)
maxime1992 01/01
Como posso adicionar z com tipo string no seu resultado
user602291
@ user602291 type Smth = XY & { z: string };,?
Qwertiy
1
Este é perfeito para a versão antiga do texto datilografado. Não consegui que a resposta aceita funcionasse para o 2.3, mas este funcionou muito bem.
K0pernikus
6

Se você preferir usar uma 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)

PS: Você encontrará muitas outras coisas úteis lá;)

Krzysztof Kaczor
fonte
5

Texto datilografado 3.5

A partir do TypeScript 3.5, o auxiliar Omit será incluído: TypeScript 3.5 RC - O tipo auxiliar Omit

Você pode usá-lo diretamente e deve remover sua própria definição do auxiliar Omit ao atualizar.

GonchuB
fonte
4

No texto datilografado 3.5+ :

interface TypographyProps {
    variant: string
    fontSize: number
}

type TypographyPropsMinusVariant = Omit<TypographyProps, "variant">
CorayThan
fonte
0

Eu faço assim:

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);
Andrew Zolotarev
fonte