¿Cómo suprimir el "error TS2533: El objeto es posiblemente 'nulo' o 'indefinido'"?

225

Tengo un type:

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

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

  maxVisibleListItems?: number
}

Declaro una variable global en cuanto a módulos:

var $protected : tSelectProtected = {};

Estoy asignando el valor adecuado en el function1()alcance:

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

Más adelante en el function2()alcance, estoy llamando:

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

Recibo un error de TypeScript:

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

Sé que puedo hacer una verificación explícita usando if ($protected.listEle) {$protected.listEle}para calmar el compilador, pero esto parece ser muy desagradable para la mayoría de los casos no triviales.

¿Cómo puede o debe manejarse esta situación sin deshabilitar las comprobaciones del compilador de TS?

grasnal
fuente

Respuestas:

99

Esta característica se denomina "comprobaciones nulas estrictas", para desactivarla asegúrese de que el --strictNullChecksindicador del compilador no esté configurado.

Sin embargo, la existencia de nullha sido descrita como The Billion Dollar Mistake , por lo que es emocionante ver lenguajes como TypeScript que introducen una solución. Recomiendo encarecidamente mantenerlo encendido.

Una forma de solucionar esto es asegurarse de que los valores nunca sean nullo undefined, por ejemplo, inicializándolos por adelantado:

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

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

Sin embargo, ¡mira la respuesta de Ryan Cavanaugh para una opción alternativa!

Douglas
fuente
8
Personalmente utilizo nulls en JavaScript "vainilla" para inicializar variables o valores de propiedades. Esto me da una respuesta directa si existe var o prop dado, pero todavía no tiene "ningún valor utilizable" o "el valor se borró en algún momento de la ejecución". Es solo por convención. Este puede no ser el mejor enfoque en TypeScript, como puedo ver en las respuestas aquí. Gracias por tus pensamientos.
grasnal
25
Incluso la inicialización no suprime "El objeto es posiblemente" indefinido "para mí en TS 2.7.2
Tyguy7
1
Sí, pero estas definiciones cambian los valores de los objetos, por ejemplo, HTMLDivElement no tiene el destino más cercano y otros eventos y propiedades de elementos básicos.
Clarence
55
¿Qué sucede si está tratando de describir un estado de alguna propiedad de Objeto Javascript, donde está la verdadera representación del estado inicial null?
Timur Mamedov
1
Agregando que hay un !operador disponible, muy similar a los de Kotlin que le permite hacer estas comprobaciones mucho más concisas
Alvaro
598

Si sabe por medios externos que una expresión no es nullo undefined, puede usar el operador de aserción no nulo !para forzar esos tipos:

// Error, some.expr may be null or undefined
let x = some.expr.thing;
// OK
let y = some.expr!.thing;
Ryan Cavanaugh
fuente
12
Gracias por informarme sobre el ! - Non-null assertion operatoroperador. Parece que la cosa aún no está bien documentada ( https://github.com/Microsoft/TypeScript/issues/11494 ), por lo que cualquiera que busque respuestas lea este http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
grasnal
99
esto tampoco tiene ningún efecto para mí en tsc v2.7.2
Tyguy7
66
@ThomasSauvajon, ¡el !operador aquí no hace lo mismo que ?en C #! Es solo una aserción del sistema de tipos ; no hará que su programa no se bloquee cuando intente leer una propiedad de nullo undefined.
Ryan Cavanaugh
2
Del manual, agregado al pinchar de Ryan: La sintaxis es postfix !: identifier!elimina nully undefineddel tipo deidentifier Esto es lo que Ryan ya dijo, pero también me parece útil.
John Hatton
55
Esto no funciona en Typecript 3.2.2. ¿Se ha eliminado?
Lars Nyström
25

Solía:

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

Alternativamente, puede usar la coerción de tipo:

const objectX = object as string

Aunque, antes de elegir una de las soluciones anteriores, considere la arquitectura a la que apunta y su impacto en el panorama general.

Árbol de Joshua
fuente
57
por alguna razón, mi TSC ignora que si la declaración, todavía considera que posiblemente no esté definida ...
Tyguy7
99
mi error NO se suprime cuando usoif(object!==undefined) object.function();
Jérémy
También se puede usar la comparación doble con nully undefined, y no es una mala práctica (solo si se usa con esos dos tipos): el evento TSLint le permitirá hacerlo. Facilita verificar si algo está definido porque en lugar de escribir null !== someObject && undefined !== someObjectpuedes usar solonull != someObject
Marecky
15

No es una respuesta directa a la pregunta del OP, pero en mi caso, tuve la siguiente configuración:

Letra de imprenta - v3.6.2
tslint -v5.20.0

Y usando el siguiente código

const refToElement = useRef(null);

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

Seguí suprimiendo el compilador para esa línea. Tenga en cuenta que, dado que es un error del compilador y no el error de linter, // tslint:disable-next-lineno funcionó. Además, según la documentación, esto debe usarse raramente, solo cuando sea necesario :

const refToElement = useRef(null);

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

ACTUALIZACIÓN :

Con Typecript 3.7, puede usar el encadenamiento opcional para resolver el problema anterior como:

refToElement?.current?.focus();
Vandesh
fuente
2
Una solución mucho mejor que deshabilitar strictNullChecks, se debe tener precaución con esto, la mayoría de las veces se desea el error de referencia nula porque puede causar dolores de cabeza reales en el futuro.
Andy Braham el
La propiedad 'getBoundingClientRect' no existe en el tipo 'nunca'.
mqliutie
En mi caso, este encadenamiento opcional no funcionó. const input = useRef<HTMLInputElement>(null);e if (input && input.current) { input.current.value = ''; }hizo el truco.
Timo
13

Esta solución funcionó para mí:

  • vaya a tsconfig.json y agregue "strictlyNullChecks": falso

ingrese la descripción de la imagen aquí

Mahesh Nepal
fuente
Esto funcionó para mí también. Aunque sigue dando errores como, por ejemplo, en las declaraciones de suscripción, no reconoce la variable de resultado, typecript quiere que declare .subscribe (result => this.result = result.json ());
Aarchie
¿Has intentado usar el operador 'mapa'? Google 'rxjs / map'. Básicamente hago: Http.get (...). Map (result => result.json ()). Subscribe (result => {haz tus cosas aquí})
Mahesh Nepal
38
no responde la pregunta OP dijo explícitamente: 'sin deshabilitar las comprobaciones del compilador TS'
pvill
44
¿Cuál es el punto al usar TypeScript y eliminar el error de linter para alertarlo? Creo que la mejor opción es lanzar el valor deseado con as100% seguro. Obtuve el caso con mongodb y el valor de retorno FindOneOrUpdate y tuve que enviarlo al esquema porque result.valuese declara como TSchema | undefinedy ya lo he consultado result.okantes
Vincent
12

Si sabe que el tipo nunca será nullo undefined, debe declararlo foo: Barsin el ?. Declarar un tipo con la ? Barsintaxis significa que podría estar indefinido, lo cual es algo que debe verificar.

En otras palabras, el compilador está haciendo exactamente lo que le pides. Si desea que sea opcional, deberá verificarlo más tarde.

ssube
fuente
1
"el compilador está haciendo exactamente lo que le pides", así que mi idea es incorrecta, gracias. Necesito cambiar el enfoque un poco.
grasnal 01 de
En mi caso, el compilador simplemente no se dio cuenta de que ya había verificado el objeto como nulo. Tengo un captador que comprueba si es nulo y lo llamo. Entonces no, no está haciendo exactamente lo que le pedí (esto no quiere decir que espero que resuelva todo) a.
CWagner
9

Este no es el problema del OP, pero recibí el mismo Object is possibly 'null'mensaje cuando había declarado un parámetro como el tipo nulo por accidente:

something: null;

en lugar de asignarle el valor nulo:

something: string = null;
thinkOfaNumber
fuente
2
Esta es la respuesta real. Frustrante cuando haces una comprobación nula explícita real y aún obtienes un Object is possibly 'null'error. Esta respuesta resuelve eso.
Ben Racicot
5

Como opción, puede usar un tipo de conversión. Si tiene este error de mecanografiado, eso significa que alguna variable tiene tipo o no está definida:

let a: string[] | undefined;

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

Asegúrese de que arealmente exista en su código.

Shevchenko Viktor
fuente
3

A partir de TypeScript 3.7 ( https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html ), ahora puede usar el ?.operador para obtener una definición indefinida al acceder a un atributo (o llamar a un método ) en un objeto nulo o indefinido:

inputEl?.current?.focus(); // skips the call when inputEl or inputEl.current is null or undefined
Jonathan Cast CONT
fuente
El operador de acceso de propiedad opcional es ?..
aventurina
2

Consejo para RxJS

A menudo tendré variables de tipo de miembro Observable<string>, y no lo inicializaré hasta ngOnInit(usando Angular). Luego, el compilador supone que no está inicializado porque no está 'definitivamente asignado en el constructor', y el compilador nunca lo va a entender ngOnInit.

Puede usar el !operador de aserción en la definición para evitar el error:

favoriteColor!: Observable<string>;

Un observable no inicializado puede causar todo tipo de problemas de tiempo de ejecución con errores como "debe proporcionar una secuencia pero proporcionó nulo". El !está bien si definitivamente sabe que va a ser puesto en algo así ngOnInit, pero puede haber casos en los que el valor se establece de alguna otra manera menos determinista.

Entonces, una alternativa que a veces usaré es:

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

Donde uninitializedse define globalmente en algún lugar como:

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

Luego, si alguna vez usa esta secuencia sin que esté definida, arrojará inmediatamente un error de tiempo de ejecución.

Simon_Weaver
fuente
No recomiendo hacer esto en todas partes, pero lo haré a veces, especialmente si confío en los parámetros de @Input establecidos desde el exterior
Simon_Weaver
2

En ReactJS, verifico en el constructor si las variables son nulas, si lo son, lo trato como una excepción y gestiono la excepción de manera adecuada. Si las variables no son nulas, el código continúa y el compilador ya no se queja después de ese punto:

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
    }
Gedeon
fuente
1

Me encontré con esto con React cuando configuré el estado y lo usé map.

En este caso, estaba haciendo una llamada de recuperación de API y el valor de la respuesta no se conocía, pero debería tener el valor "Respuesta". Usé un tipo personalizado para esto, pero porque el valor podría sernull , obtuve un error TS de todos modos. Permitir que el tipo sea nullno lo arregla; alternativamente, podría usar un default parameter value, pero esto fue complicado para mi caso.

Lo superé al proporcionar un valor predeterminado en el caso de que la respuesta estuviera vacía con solo usar un operador ternario:

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

En mecanografiado puede hacer lo siguiente para suprimir el error:

let subString?: string;

subString > !null; - Tenga en cuenta el signo de exclamación agregado antes de nulo.

usuario3834142
fuente
0

Intenta llamar a un objeto como este:

(<any>Object).dosomething

Este error se produjo porque los ha declarado como opcionales usando ?. Ahora Typecript realiza una verificación estricta y no permitirá hacer nada que pueda ser undefined. Por lo tanto, puedes usar (<any>yourObject)aquí.

Ankita Srivastava
fuente