Search code examples
typescriptobjectany

Restrict typescript to insure reference to 'any' object's properties is checked


I have a JS object myObject, which is of type any (I can't change the type, since it comes from a library).

If I try to access a property from myObject I get no errors from typescript, since its type is any. But myObject could be undefined, and cause a crash.

Is it possible to get typescript to give an error in this case?

For example:

console.log(myObject.myProperty) // <-- if myObject is undefined, this will crash.

What I would like:

console.log(myObject.myProperty) // <-- typescript gives error
console.log(myObject?.myProperty) // <-- typescript gives no error

Is there a tsconfig for changing this behavior?


I am not looking for a solution using type unknown.


Solution

  • No, TypeScript does not have support for a stricter interpretation of the any type in which member access is disallowed unless it is known to be safe. Nor have I found any existing request for this particular feature. There was a proposal for a --strictAny, which would have been different, but this was eventually closed in microsoft/TypeScript#24737 saying, among other things, that extra complexity around any really didn't seem to be worth it, especially because there are many places in real world code where any is intentionally used as a way to turn off type checking. So it is unlikely that TypeScript will add such functionality.

    Instead, you could use a linter, like TypeScript ESLint. There is a no-unsafe-member-access rule which "disallows member access on any variable that is typed as any". This will cause the desired error to appear, but it will also cause undesired errors where you have done the proper type check. That is, it is more restrictive than you want:

    declare const myObject: any;
    myObject.myProperty // warning: unsafe access 😊
    myObject?.myProperty // warning: unsafe access ☹
    

    It doesn't look like there's any "perfect" way to proceed. I'd recommend that you copy the value to a variable of a non-any type:

    type MyAny = { [k: string]: any } | undefined | null;
    const _myObject: MyAny = myObject
    _myObject.myProperty; // error
    _myObject?.myProperty; // okay
    

    Or write a type checking function that narrows any to more safely indexable type:

    function nonNullish(x: any): x is { [k: string]: any } {
      return x != null;
    }
    if (nonNullish(myObject)) {
      myObject.myProperty // okay
    }
    

    Or maybe even push back on the typings provider for the library and say that any is too loose of a type if the value might really be undefined or null at runtime. (If it can't, then the other option is to just stop worrying about it until and unless it does happen.)

    TS-ESLint Playground link to code