Como suprimir o "erro TS2533: o objeto é possivelmente 'nulo' ou 'indefinido'"?


225

Eu tenho um type:

type tSelectProtected = {
  handleSelector?: string,
  data?: tSelectDataItem[],

  wrapperEle?: HTMLElement,
  inputEle?: HTMLElement,
  listEle?: HTMLElement,
  resultEle?: HTMLElement,

  maxVisibleListItems?: number
}

Declaro uma variável global em módulo:

var $protected : tSelectProtected = {};

Estou atribuindo valor adequado no function1()escopo:

$protected.listEle = document.createElement('DIV');

Mais tarde no function2()escopo, estou chamando:

$protected.listEle.classList.add('visible');

Estou recebendo erro do TypeScript:

error TS2533: Object is possibly 'null' or 'undefined'

Eu sei que posso fazer uma verificação explícita usando if ($protected.listEle) {$protected.listEle}para acalmar o compilador, mas isso parece ser pouco prático para a maioria dos casos não triviais.

Como essa situação pode ou deve ser tratada sem desativar as verificações do compilador TS?

Respostas:


99

Esse recurso é chamado de "verificações nulas rigorosas", para desativá-lo e garantir que o --strictNullCheckssinalizador do compilador não esteja definido.

No entanto, a existência de nulltem sido descrito como The Billion Dollar Mistake , por isso é emocionante ver línguas como o original datilografado introduzir uma correção. Eu recomendo fortemente mantê-lo ligado.

Uma maneira de corrigir isso é garantir que os valores nunca sejam nullou undefined, por exemplo, inicializando-os com antecedência:

interface SelectProtected {
    readonly wrapperElement: HTMLDivElement;
    readonly inputElement: HTMLInputElement;
}

const selectProtected: SelectProtected = {
    wrapperElement: document.createElement("div"),
    inputElement: document.createElement("input")
};

Veja a resposta de Ryan Cavanaugh para uma opção alternativa!


8
Pessoalmente, uso nulls no JavaScript "vanilla" para inicializar valores de variáveis ​​ou propriedades. Isso me dá uma resposta direta, se existe dado var ou prop, mas ainda não há "valor utilizável" ou "o valor foi limpo em algum momento da execução". É apenas por convenção. Essa pode não ser a melhor abordagem no TypeScript, como posso ver pelas respostas aqui. Obrigado por seus pensamentos.
#

25
Mesmo a inicialização não suprime "O objeto é possivelmente 'indefinido'" para mim no TS 2.7.2
Tyguy7

1
Sim, mas essas definições alteram os valores dos objetos, por exemplo, HTMLDivElement não tem destino mais próximo e outros eventos e propriedades de elementos básicos.
Clarence

5
E se você estiver tentando descrever um estado de alguma propriedade Javascript Object, onde está a verdadeira representação do estado inicial null?
Timur Mamedov

1
Acrescentando que há um !operador disponível, muito semelhantes aos em Kotlin que permite fazer essas verificações muito mais concisas
Alvaro

598

Se, por meio externo, você souber que uma expressão não é nullou undefined, poderá usar o operador de asserção não nulo !para coagir esses tipos:

// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;

12
Obrigado por me informar sobre o ! - Non-null assertion operatoroperador. Parece que a coisa ainda não está bem documentada ( https://github.com/Microsoft/TypeScript/issues/11494 ), para que qualquer pessoa que esteja procurando respostas leia isso http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
grasnal 01/11/16

9
isso também não tem nenhum efeito para mim em v2.7.2 tsc
Tyguy7

6
@ThomasSauvajon o !operador aqui não faz o mesmo que ?em C #! É apenas uma afirmação de sistema de tipos ; isso não fará com que o seu programa não falhe ao tentar ler uma propriedade de nullou undefined.
22619 Ryan Cavanaugh

2
Do manual, adicionado ao estímulo de Ryan: A sintaxe é postfix !: identifier!remove nulle undefineddo tipoidentifier Isso é o que Ryan já disse, mas também acho útil.
John Hatton

5
Isso não funciona no Typescript 3.2.2. Foi removido?
Lars Nyström

25

Eu usei:

if (object !== undefined) {
    // continue - error suppressed when used in this way.
}

Como alternativa, você pode usar coerção de tipo:

const objectX = object as string

Embora, antes de escolher uma das soluções alternativas acima, considere a arquitetura que você está almejando e o impacto para a imagem maior.


57
por algum motivo meus ignora TSC que se instrução, ainda considera-lo para possivelmente ser indefinido ...
Tyguy7

9
meu erro não é suprimido quando eu usoif(object!==undefined) object.function();
Jérémy

Também é possível usar a comparação dupla com nulle undefined, e isso não é uma prática ruim (somente se for usado com esses dois tipos) - o evento TSLint permitirá que você faça isso. Facilita verificar se algo está definido, porque em vez de escrever null !== someObject && undefined !== someObjectvocê pode usar apenasnull != someObject
Marecky

14

Não é uma resposta direta à pergunta do OP, mas no meu caso, eu tinha a seguinte configuração -

Texto v3.6.2
datilografado - tslint -v5.20.0

E usando o seguinte código

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     refToElement.current.focus(); // Object is possibly 'null' (for refToElement.current)
}

Eu segui em frente suprimindo o compilador para essa linha. Observe que, como é um erro do compilador e não o erro do linter, // tslint:disable-next-linenão funcionou. Além disso, de acordo com a documentação, isso deve ser usado raramente, somente quando necessário -

const refToElement = useRef(null);

if (refToElement && refToElement.current) {
     // @ts-ignore: Object is possibly 'null'.
     refToElement.current.focus(); 
}

ATUALIZAÇÃO :

Com o Typecript 3.7, você pode usar o encadeamento opcional para resolver o problema acima como -

refToElement?.current?.focus();

2
Solução muito melhor do que desabilitar o strictNullChecks, cuidado deve ser usado com isso, na maioria das vezes você deseja o erro de referência nula, pois pode causar dores de cabeça reais no caminho.
Andy Braham

A propriedade 'getBoundingClientRect' não existe no tipo 'never'.
mqliutie

No meu caso, esse encadeamento opcional não funcionou. const input = useRef<HTMLInputElement>(null);e if (input && input.current) { input.current.value = ''; }fez o truque.
Timo

13

Esta solução funcionou para mim:

  • vá para tsconfig.json e adicione "strictNullChecks": false

insira a descrição da imagem aqui


Isso funcionou para mim também. Embora ainda esteja dando erro como, por exemplo, nas instruções de assinatura, não está reconhecendo a variável de resultado, o texto datilografado deseja que declare .subscribe (result => this.result = result.json ());
Aarchie

Você já tentou usar o operador 'map'? Google 'rxjs / map'. Eu basicamente faço:. Http.get (...) mapear (resultado => result.json ()) subscrever (resultado => {fazer suas coisas aqui})..
Mahesh Nepal

38
não responde a pergunta. O OP disse explicitamente: 'sem desabilitar as verificações do compilador TS'
pvill 24/03/18

4
Qual é o objetivo do TypeScript e remover o erro do linter para alertá-lo? Eu acho que a melhor opção é converter o valor desejado com as100% de certeza. Eu tenho o caso com MongoDB e valor de retorno FindOneOrUpdate e eu tive que lançá-lo para o esquema porque a result.valueé declarada como TSchema | undefinede eu já verificar com result.okantes
Vincent

12

Se você souber que o tipo nunca será nullou undefined, deverá declará-lo como foo: Barsem o ?. Declarar um tipo com a ? Barsintaxe significa que ele pode estar indefinido, o que é algo que você precisa verificar.

Em outras palavras, o compilador está fazendo exatamente o que você está pedindo. Se você quiser que seja opcional, precisará fazer a verificação mais tarde.


1
"O compilador está fazendo exatamente o que você está pedindo", então minha ideia está errada, obrigado. Eu preciso mudar um pouco a abordagem.
#

No meu caso, o compilador simplesmente não percebeu que eu já havia verificado o objeto como nulo. Eu tenho um getter que verifica nulo e chama esse getter. Então não, não está fazendo exatamente o que eu pedi (isso não quer dizer que espero que descubra tudo).
CWagner 27/03/19

9

Este não é o problema do OP, mas recebi a mesma Object is possibly 'null'mensagem quando declarei um parâmetro como o tipo nulo por acidente:

something: null;

em vez de atribuir o valor nulo:

something: string = null;

2
Esta é a resposta real. Frustrante quando você faz uma verificação nula explícita real e ainda recebe Object is possibly 'null'erro. Esta resposta resolve isso.
Ben Racicot

5

Como opção, você pode usar uma conversão de tipo. Se você tiver esse erro do texto datilografado, isso significa que alguma variável tem tipo ou é indefinida:

let a: string[] | undefined;

let b: number = a.length; // [ts] Object is possibly 'undefined'
let c: number = (a as string[]).length; // ok

Verifique se arealmente existe no seu código.



2

Dica para RxJS

Muitas vezes terei variáveis ​​de membro do tipo Observable<string>e não a inicializarei até ngOnInit(usando Angular). O compilador então assume que ele não foi inicializado, pois não está 'definitivamente designado no construtor' - e o compilador nunca vai entender ngOnInit.

Você pode usar o !operador de asserção na definição para evitar o erro:

favoriteColor!: Observable<string>;

Um observável não inicializado pode causar todos os tipos de problemas de tempo de execução com erros como 'você deve fornecer um fluxo, mas você forneceu nulo'. Tudo !bem se você definitivamente sabe que será definido de alguma forma ngOnInit, mas pode haver casos em que o valor é definido de alguma outra maneira menos determinística.

Portanto, uma alternativa que usarei às vezes é:

public loaded$: Observable<boolean> = uninitialized('loaded');

Onde uninitializedé definido globalmente em algum lugar como:

export const uninitialized = (name: string) => throwError(name + ' not initialized');

Então, se você usar esse fluxo sem que seja definido, lançará imediatamente um erro de tempo de execução.


Eu não recomendo fazer isso em todos os lugares, mas eu vou fazer isso às vezes - especialmente se depender de parâmetros @Input definidos a partir do exterior
Simon_Weaver

2

No ReactJS, verifico no construtor se as variáveis ​​são nulas, se tratam isso como uma exceção e gerencio a exceção adequadamente. Se as variáveis ​​não forem nulas, o código continua e o compilador não reclama mais depois desse ponto:

private variable1: any;
private variable2: any;

constructor(props: IProps) {
    super(props);

    // i.e. here I am trying to access an HTML element
    // which might be null if there is a typo in the name
    this.variable1 = document.querySelector('element1');
    this.variable2 = document.querySelector('element2');

    // check if objects are null
    if(!this.variable1 || !this.variable2) {
        // Manage the 'exception', show the user a message, etc.
    } else {
        // Interpreter should not complain from this point on
        // in any part of the file
        this.variable1.disabled = true; // i.e. this line should not show the error
    }

1

Corri para isso com o React ao definir o estado e o uso map.

Nesse caso, eu estava fazendo uma chamada de busca da API e o valor da resposta não era conhecido, mas deveria ter o valor "Resposta". Usei um tipo personalizado para isso, mas como o valor poderia ser null, recebi um erro de TS de qualquer maneira. Permitir que o tipo seja nullnão o corrige; alternativamente, você pode usar um default parameter value, mas isso foi confuso para o meu caso.

Eu o superei fornecendo um valor padrão no caso de a resposta estar vazia usando apenas um operador ternário:

this.setState({ record: (response.Answer) ? response.Answer : [{ default: 'default' }] });

0

No texto datilografado, você pode fazer o seguinte para suprimir error:

let subString?: string;

subString > !null; - Observe o ponto de exclamação adicionado antes de nulo.


0

Tente chamar um objeto como este:

(<any>Object).dosomething

Este erro ocorreu porque você os declarou como opcional ?. Agora, o Typecript faz uma verificação rigorosa e não permite fazer nada que possa ser undefined. Portanto, você pode usar (<any>yourObject)aqui.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.