Comment supprimer «erreur TS2533: l'objet est peut-être« nul »ou« non défini »»?


225

J'ai un type:

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

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

  maxVisibleListItems?: number
}

Je déclare une variable globale par module:

var $protected : tSelectProtected = {};

J'attribue une valeur appropriée dans la function1()portée:

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

Plus tard dans la function2()portée, j'appelle:

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

Je reçois une erreur TypeScript:

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

Je sais que je peux faire une vérification explicite en utilisant if ($protected.listEle) {$protected.listEle}pour calmer le compilateur mais cela semble être très peu pratique pour la plupart des cas non triviaux.

Comment cette situation peut ou doit être gérée sans désactiver les vérifications du compilateur TS?

Réponses:


99

Cette fonctionnalité est appelée "contrôles null stricts", pour la désactiver, assurez-vous que l' --strictNullChecksindicateur du compilateur n'est pas défini.

Cependant, l'existence de nulla été décrite comme The Billion Dollar Mistake , il est donc passionnant de voir des langages tels que TypeScript introduire un correctif. Je recommande fortement de le garder allumé.

Une façon de résoudre ce problème consiste à s'assurer que les valeurs ne sont jamais nullou undefined, par exemple en les initialisant à l'avance:

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

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

Voir la réponse de Ryan Cavanaugh pour une option alternative, cependant!


8
Personnellement, j'utilise des nulls en JavaScript "vanille" pour initialiser les valeurs des variables ou des propriétés. Cela me donne une réponse directe si var ou prop donné existe mais qu'il n'a "pas encore de valeur utilisable" ou "la valeur a été effacée à un certain point d'exécution". C'est juste par convention. Ce n'est peut-être pas une meilleure approche dans TypeScript comme je peux le voir par les réponses ici. Merci pour vos pensées.
— grasnal

25
Même l'initialisation ne supprime pas "L'objet est peut-être" indéfini "" pour moi dans TS 2.7.2
— Tyguy7

1
Oui, mais ces définitions modifient les valeurs des objets, par exemple, HTMLDivElement n'a pas la cible la plus proche et d'autres événements et propriétés élémentaires de base.
— Clarence

5
Que faire si vous essayez de décrire un état d'une propriété d'objet Javascript, où se trouve la véritable représentation de l'état de départ null?
— Timur Mamedov

1
Ajoutant qu'il existe un !opérateur disponible, très similaire à ceux de Kotlin qui vous permet de rendre ces contrôles beaucoup plus concis
— Alvaro

599

Si vous savez par des moyens externes qu'une expression n'est pas nullou undefined, vous pouvez utiliser l'opérateur d'assertion non nul !pour contraindre ces types:

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

12
Merci de m'avoir informé de l' ! - Non-null assertion operatoropérateur. Il semble que la chose ne soit pas encore bien documentée ( https://github.com/Microsoft/TypeScript/issues/11494 ), donc quiconque cherche des réponses lira ce http://stackoverflow.com/questions/38874928/operator-in-typescript -after-object-method
— grasnal

9
cela n'a également aucun effet pour moi sur tsc v2.7.2
— Tyguy7

6
@ThomasSauvajon l' !opérateur ici ne fait pas la même chose qu'en ?C #! Ce n'est qu'une assertion de système de type ; cela n'entraînera pas le plantage de votre programme lors de la tentative de lecture d'une propriété à partir de nullou undefined.
— Ryan Cavanaugh

2
Extrait du manuel, ajouté chez Ryan's prodding: La syntaxe est postfixe !: identifier!supprime nullet undefineddu type deidentifier Voici ce que Ryan a déjà dit, mais je trouve cela utile aussi.
— John Hatton

5
Cela ne fonctionne pas dans Typescript 3.2.2. At-il été supprimé?
— Lars Nyström

25

J'ai utilisé:

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

Alternativement, vous pouvez utiliser la contrainte de type:

const objectX = object as string

Bien que, avant de choisir l'une des solutions de contournement ci-dessus, veuillez considérer l'architecture que vous visez et son impact sur la vue d'ensemble.


57
pour une raison quelconque, mon TSC ignore que si la déclaration, le considère toujours comme étant indéfini ...
— Tyguy7

9
mon erreur n'est PAS supprimée lorsque j'utiliseif(object!==undefined) object.function();
— Jérémy

On peut également utiliser une double comparaison avec nullet undefined, et ce n'est pas une mauvaise pratique (uniquement si vous utilisez avec ces deux types) - l'événement TSLint vous permettra de le faire. Il facilite la vérification si quelque chose est défini, car au lieu d'écrire, null !== someObject && undefined !== someObjectvous pouvez utiliser simplementnull != someObject
— Marecky

15

Pas une réponse directe à la question du PO, mais dans mon cas, j'avais la configuration suivante -

Tapuscrit - v3.6.2
tslint -v5.20.0

Et en utilisant le code suivant

const refToElement = useRef(null);

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

J'ai continué en supprimant le compilateur pour cette ligne. Notez que comme il s'agit d'une erreur de compilation et non d'une erreur de linter, cela // tslint:disable-next-linen'a pas fonctionné. En outre, selon la documentation, cela devrait être utilisé rarement, uniquement lorsque cela est nécessaire -

const refToElement = useRef(null);

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

MISE À JOUR :

Avec Typescript 3.7, vous pouvez utiliser le chaînage facultatif , pour résoudre le problème ci-dessus comme -

refToElement?.current?.focus();

2
Une bien meilleure solution que de désactiver le strictNullChecks, la prudence devrait être utilisée avec cela, la plupart du temps vous voulez l'erreur de référence nulle car elle peut causer de vrais maux de tête sur la route.
— Andy Braham

La propriété «getBoundingClientRect» n'existe pas sur le type «jamais».
— mqliutie

Dans mon cas, ce chaînage facultatif n'a pas fonctionné. const input = useRef<HTMLInputElement>(null);et a if (input && input.current) { input.current.value = ''; }fait l'affaire.
— Timo

13

Cette solution a fonctionné pour moi:

  • allez sur tsconfig.json et ajoutez "strictNullChecks": false

entrez la description de l'image ici


Cela a également fonctionné pour moi. Bien qu'il donne toujours une erreur comme, par exemple dans les instructions subscribe, il ne reconnaît pas la variable de résultat, typescript veut qu'il déclare .subscribe (result => this.result = result.json ());
— Aarchie

Avez-vous essayé d'utiliser l'opérateur 'map'? Google «rxjs / map». Je fais essentiellement:. Http.get (...). Map (result => result.json ()). Subscribe (result => {do your stuff here})
— Mahesh Népal

38
ne répond pas à la question. OP a dit explicitement: «sans désactiver les vérifications du compilateur TS»
— pvill

4
À quoi bon utiliser TypeScript et supprimer l'erreur de linter pour vous alerter? Je pense que la meilleure option est de lancer la valeur souhaitée avec assi vous êtes sûr à 100%. J'ai eu le cas avec mongodb et la valeur de retour FindOneOrUpdate et j'ai dû le caster dans le schéma car le result.valueest déclaré comme TSchema | undefinedet j'ai déjà vérifié result.okavant
— Vincent

12

Si vous savez que le type ne sera jamais nullou undefined, vous devez le déclarer comme foo: Barsans ?. Déclarer un type avec le? Bar syntaxe signifie qu'il pourrait potentiellement être indéfini, ce que vous devez vérifier.

En d'autres termes, le compilateur fait exactement ce que vous lui demandez. Si vous voulez que ce soit facultatif, vous devrez le vérifier plus tard.


1
"le compilateur fait exactement ce que vous lui demandez" donc mon idée est fausse, merci. J'ai besoin de changer un peu d'approche.
— grasnal

Dans mon cas, le compilateur ne s'est tout simplement pas rendu compte que j'avais déjà vérifié la nullité de l'objet. J'ai un getter qui vérifie null et appelle ce getter. Donc non, il ne fait pas exactement ce que je lui ai demandé (cela ne veut pas dire que je m'attends à ce qu'il comprenne tout).
— CWagner

9

Ce n'est pas le problème de l'OP, mais j'ai reçu le même Object is possibly 'null'message lorsque j'avais déclaré un paramètre comme type nul par accident:

something: null;

au lieu de lui attribuer la valeur null:

something: string = null;

2
Telle est la vraie réponse. Frustrant lorsque vous effectuez une vérification null explicite réelle et obtenez toujours une Object is possibly 'null'erreur. Cette réponse résout cela.
— Ben Racicot

5

En option, vous pouvez utiliser un transtypage de type. Si vous avez cette erreur de typescript, cela signifie qu'une variable a un type ou n'est pas définie:

let a: string[] | undefined;

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

Assurez-vous que acela existe vraiment dans votre code.



2

Astuce pour RxJS

J'ai souvent des variables membres de type Observable<string>, et je ne l'initialiserai pas avant ngOnInit(en utilisant Angular). Le compilateur suppose alors qu'il n'est pas initialisé car il n'est pas «définitivement attribué dans le constructeur» - et le compilateur ne comprendra jamais ngOnInit.

Vous pouvez utiliser l' !opérateur d'assertion sur la définition pour éviter l'erreur:

favoriteColor!: Observable<string>;

Un observable non initialisé peut provoquer toutes sortes de problèmes d'exécution avec des erreurs comme «vous devez fournir un flux mais vous avez fourni null». C'est !bien si vous savez vraiment que cela va être réglé de quelque manière que ce soit ngOnInit, mais il peut y avoir des cas où la valeur est définie d'une autre manière moins déterministe.

Une alternative que je vais parfois utiliser est donc:

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

Où uninitializedest défini globalement quelque part comme:

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

Ensuite, si vous utilisez ce flux sans qu'il soit défini, il générera immédiatement une erreur d'exécution.


Je ne recommande pas de le faire partout, mais je le ferai parfois - surtout si je me fie aux paramètres @Input définis de l'extérieur
— Simon_Weaver

2

Dans ReactJS, je vérifie dans le constructeur si les variables sont nulles, si elles le sont, je le traite comme une exception et gère l'exception de manière appropriée. Si les variables ne sont pas nulles, le code continue et le compilateur ne se plaint plus après ce point:

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

J'ai rencontré cela avec React lors de la définition de l'état et de l'utilisation map .

Dans ce cas, je faisais un appel de récupération d'API et la valeur de la réponse n'était pas connue, mais devrait avoir une valeur "Answer". J'ai utilisé un type personnalisé pour cela, mais comme la valeur pourrait être null, j'ai quand même eu une erreur TS. Permettre au type d'être nullne le résout pas; vous pouvez également utiliser undefault parameter value , mais c'était désordonné pour mon cas.

Je l'ai surmonté en fournissant une valeur par défaut dans le cas où la réponse était vide en utilisant simplement un opérateur ternaire:

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

0

En dactylographie, vous pouvez effectuer les opérations suivantes pour supprimer error:

let subString?: string;

subString > !null; - Notez le point d'exclamation ajouté avant null.


0

Essayez d'appeler un objet comme ceci:

(<any>Object).dosomething

Cette erreur est survenue car vous les avez déclarés comme facultatifs à l'aide de ?. Désormais, Typescript effectue une vérification stricte et ne permet plus rien undefined. Par conséquent, vous pouvez utiliser (<any>yourObject)ici.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.