Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

269
Visualizações
Typescript error when multiple optional types are used

This an example of the error:

interface Block {
  id: string;
}

interface TitleBlock extends Block  {
  data: {
    text: "hi",
    icon: "hi-icon"
  }
}

interface SubtitleBlock extends Block  {
  data: {
    text: "goodbye",
  }
}

interface CommentBlock extends Block {
  author: string; 
}

type BlockTypes = TitleBlock | SubtitleBlock | CommentBlock

function mapper(block : BlockTypes) {
    if(block?.data?.text){  // TS Error here!!! 
      /** do something */
    }
}

Live example

I want to do something in the function when the block has a specific attribute but TS does not allow me to do so even when there are type in BlockTypes that have that property.

What is the best way to manage this types of functionalities?

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

The optional chaining operator (?.) only guards against null and undefined; it does not filter a union-typed expression to those members known to contain that key. See this comment in Microsoft/TypeScript#33736 for a canonical answer.


The issue is that object types in TypeScript are open and are allowed to contain more properties than the compiler knows about. So if block.data is truthy, it unfortunately does not imply that block.data.text exists:

const oof = {
  id: "x",
  author: "weirdo",
  data: 123
}
mapper(oof); // accepted

Here oof is a valid CommentBlock, and so mapper(oof) is allowed, and oof.data is truthy, but oof.data.text is undefined, and you will have a problem if you try to treat it like a string.

So it would be unsound (that is, not type safe) to allow optional chaining to filter unions the way you want.


The workaround here, if you don't think that oof-like cases are likely, is to use the in operator as a type guard:

function mapper(block: BlockTypes) {
  if ("data" in block) {
    block.data.text.toUpperCase()
  }
}

This works fine with no compiler error. Of course, it's still unsound in exactly the same way as narrowing with ?. would be... if you call mapper(oof) there are no compiler errors but you will get a runtime error. So you should be careful.

It's a little weird that TypeScript allows in to behave this way but does not allow other similar constructs. You can read the discussion in microsoft/TypeScript#10485 to see why that happened. Mostly it seems to be that when people write "foo" in bar they rarely do the wrong thing with it, but that other constructs like bar.foo && bar.foo.baz are misused more often. But that's according to the TS team, not me. 🤷‍♂️

Playground link to code

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda