"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Dominando TypeScript: Compreendendo o poder das extensões

Dominando TypeScript: Compreendendo o poder das extensões

Publicado em 2024-11-06
Navegar:691

Mastering TypeScript: Understanding the Power of extends

A palavra-chave extends no TypeScript é uma espécie de canivete suíço. É usado em vários contextos, incluindo herança, genéricos e tipos condicionais. Compreender como usar extensões de maneira eficaz pode levar a um código mais robusto, reutilizável e de tipo seguro.

Herança usando extensões

Um dos principais usos de extensões é na herança, permitindo criar novas interfaces ou classes que se baseiam nas existentes.

interface User {
  firstName: string;
  lastName: string;
  email: string;
}

interface StaffUser extends User {
  roles: string[];
  department: string;
}

const regularUser: User = {
  firstName: "John",
  lastName: "Doe",
  email: "[email protected]"
};

const staffMember: StaffUser = {
  firstName: "Jane",
  lastName: "Smith",
  email: "[email protected]",
  roles: ["Manager", "Developer"],
  department: "Engineering"
};

Neste exemplo, StaffUser estende User, herdando todas as suas propriedades e adicionando novas. Isso nos permite criar tipos mais específicos com base em tipos mais gerais.

Herança de classe

A palavra-chave extends também é usada para herança de classe:

class Animal {
  constructor(public name: string) {}

  makeSound(): void {
    console.log("Some generic animal sound");
  }
}

class Dog extends Animal {
  constructor(name: string, public breed: string) {
    super(name);
  }

  makeSound(): void {
    console.log("Woof! Woof!");
  }

  fetch(): void {
    console.log(`${this.name} is fetching the ball!`);
  }
}

const myDog = new Dog("Buddy", "Golden Retriever");
myDog.makeSound(); // Output: Woof! Woof!
myDog.fetch(); // Output: Buddy is fetching the ball!

Aqui, Dog estende Animal, herdando suas propriedades e métodos, e também adicionando seus próprios.

Restrições de tipo em genéricos

A palavra-chave extends é crucial ao trabalhar com genéricos, permitindo-nos restringir os tipos que podem ser usados ​​com uma função ou classe genérica.

interface Printable {
  print(): void;
}

function printObject(obj: T) {
  obj.print();
}

class Book implements Printable {
  print() {
    console.log("Printing a book.");
  }
}

class Magazine implements Printable {
  print() {
    console.log("Printing a magazine.");
  }
}

const myBook = new Book();
const myMagazine = new Magazine();

printObject(myBook);      // Output: Printing a book.
printObject(myMagazine);  // Output: Printing a magazine.
// printObject(42);       // Error, number doesn't have a 'print' method
  1. interface Printable: Aqui, definimos uma interface chamada Printable. Esta interface declara um contrato que qualquer classe que a implemente deve aderir. O contrato especifica que qualquer classe que implemente Printable deve fornecer um método chamado print que não receba argumentos e retorne void
  2. function printObject(obj: T): Esta é uma função genérica chamada printObject. É necessário um único argumento chamado obj, que é o tipo T. O parâmetro de tipo T é restrito a tipos que estendem (implementam) a interface Printable que pode ser usada como argumento para esta função.
  3. a classe Book implementa Printable e a classe Magazine implementa Printable: Aqui, definimos duas classes, Book e Magazine, ambas implementando a interface Printable. Isso significa que essas classes devem fornecer um método de impressão conforme exigido pelo contrato da interface Printable.
  4. const meuLivro = new Livro(); e const myMagazine = new Magazine();: Criamos instâncias das classes Book e Magazine.
  5. printObject(meuLivro); e printObject(myMagazine);: Chamamos a função printObject com as instâncias de Book e Magazine. Como as classes Book e Magazine implementam a interface Printable, elas atendem à restrição do parâmetro de tipo T extends Printable. Dentro da função, o método print da classe apropriada é chamado, resultando na saída esperada.
  6. // printObject(42);: Se tentarmos chamar printObject com um tipo que não implementa a interface Printable, como o número 42, o TypeScript gerará um erro. Isso ocorre porque a restrição de tipo não é satisfeita, pois o número não possui um método de impressão conforme exigido pela interface Printable.
Em resumo, a palavra-chave extends no contexto da função printObject(obj: T) é usada para garantir que o tipo T usado como argumento esteja de acordo com o contrato definido pela interface Printable. Isso garante que apenas tipos com um método print possam ser usados ​​com a função printObject, impondo um comportamento e um contrato específicos para o uso da função.

Tipos Condicionais

T estende U ? X: S
T extends U ? X : Y
    T é o tipo que está sendo verificado
  • U é o tipo de condição contra o qual T está sendo verificado.
  • X é o tipo que o tipo condicional avalia se T estende (é atribuível a) U
  • Y é o tipo que o tipo condicional avalia se T não estender U
type ExtractNumber = T estende o número? T: nunca; digite NumberOrNever = ExtractNumber; // número digite StringOrNever = ExtractNumber; // nunca
T extends U ? X : Y
Aqui, o tipo ExtractNumber usa um parâmetro de tipo T. O tipo condicional verifica se T estende o tipo de número. se isso acontecer, o tipo será resolvido para T (que é o tipo numérico). Caso contrário, o tipo será resolvido como nunca.

A palavra-chave estende com tipos de união

Agora, vamos considerar a expressão A | B | C estende A. Isso pode parecer contra-intuitivo a princípio, mas no TypeScript, essa condição é na verdade falsa. Eis o porquê:

    No TypeScript, quando você usa extensões com um tipo de união no lado esquerdo, é equivalente a perguntar:
  1. "Todos os tipos possíveis nesta união podem ser atribuídos ao tipo à direita?"
  2. Em outras palavras, A | B | C estende A está perguntando:
  3. "A pode ser atribuído a A, E B pode ser atribuído a A, E C pode ser atribuído a A?"
  4. Embora A possa certamente ser atribuído a A, B e C podem não ser atribuíveis a A (a menos que sejam subtipos de A), portanto o resultado geral é falso.
tipo Fruta = "maçã" | "banana" | "cereja"; digite CitrusFruit = "limão" | "laranja"; type IsCitrus = T estende CitrusFruit? verdadeiro: falso; digite Teste1 = IsCitrus; // verdadeiro digite Test2 = IsCitrus; // falso digite Test3 = IsCitrus; // falso
T extends U ? X : Y
Neste exemplo, IsCitrus é falso porque nem todas as frutas na união Fruit são CitrusFruit.

Melhores práticas e dicas

  • Use extensões para relacionamentos significativos: use herança apenas quando houver um relacionamento "é-um" claro entre os tipos.
  • Prefira composição em vez de herança: Em muitos casos, a composição (usando interfaces e interseções de tipos) pode ser mais flexível do que a herança de classes.
  • Seja cauteloso com cadeias de herança profundas: a herança profunda pode tornar o código mais difícil de entender e manter.
  • Aproveite tipos condicionais para APIs flexíveis: use tipos condicionais com extensões para criar APIs que se adaptam com base em tipos de entrada.
  • Use extensões em genéricos para criar funções reutilizáveis ​​e com segurança de tipo: Isso permite que você escreva funções que funcionam com uma variedade de tipos, mantendo a segurança de tipo
Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/hasanm95/mastering-typescript-understanding-the-power-of-extends-1n2o?1 Se houver alguma violação, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3