4

I'm currently converting a large TypeScript codebase to strict null-checks. The codebase has many types with optional members:

interface MyInterface {
  member1?: number;
  member2?: string;
}

Furthermore, it uses a type Nullable<T> = T | null, and has many return null statements.

Now I'm facing many compiler errors which basically state that T | null cannot be converted to T | undefined, or vice versa, like in this example:

interface MyInterface {
  member1?: number;
  member2?: string;
}

const myFunction = () => {
  return null;
}

const item: MyInterface = {};
item.member1 = myFunction();      // <== can't assign null to undefined

I love strict null-checking in TypeScript, but I have no use for the distinction between null and undefined. I can appreciate that there are some use cases where it makes sense to distinguish between null and undefined, but in this project, it really does not play an important part. These functions that return null just return nothing - it does not matter whether it is null or undefined. Same goes for the optional members - they are either set to a value, or they are not.

I also prefer to not convert the member1?: number; to member1: Nullable<number>;, and to leave the return null as they are

Can I disable the distinction between undefined and null, at least in TypeScript?

Jonas Sourlier
  • 13,684
  • 16
  • 77
  • 148
  • I mean, no? You have to change your types. Convert `member1?: number` to `member1?: number | null` and any reference to `null` or `undefined` separately should probably be changed to the union `null | undefined`. If someone can suggest an answer other than "no" I'd be all ears but I don't imagine it's possible – jcalz Sep 15 '20 at 16:21
  • 1
    @jcalz If it is not possible, this would be a great addition to TypeScript. In 99.9% of all cases, the distinction between null and undefined does not contribute anything useful. – Jonas Sourlier Sep 15 '20 at 16:24
  • I second jcalz's comment. Pretty sure it's not possible. Additionally, it wouldn't make sense to disable the differenciation, as they are in fact two different types in JavaScript. `null === undefined` will yield `false` as they are in fact not the same, even though they are often treated the same. Just don't use null in your codebase if you don't differentiate it from undefined anyway. – pascalpuetz Sep 15 '20 at 16:30
  • @pascalpuetz Yes, they are different types in Javascript. My point is, we can enable or disable the strict null-checking in TypeScript. When It is disabled, we can assign `null` to an optional member (i.e. to `number | undefined`) without TypeScript saying anything. So, without strict null-checking, TypeScript does not really care whether I use `null` or `undefined`. My question is, can we enable strict null-checking **without** enabling this difference? – Jonas Sourlier Sep 15 '20 at 16:49
  • @cheesus you can always open [an issue](https://github.com/microsoft/TypeScript/issues) proposing such a feature, but I don't know that it would get any traction. It might even be declined outright. – jcalz Sep 15 '20 at 16:58

1 Answers1

1

I'd better to wrote a comment, but since I want to show you some code example I leave it as answer.

If I were you, I would add some wrapper for all your interfaces with optional (weak) properties.

Here is an example of such wrapper:


type MapNullable<T> = {
    [P in keyof T]: undefined extends T[P] ? (T[P] | null) : T[P]
}

interface MyInterface {
  member1?: number;
  member2?: string;
}

const myFunction = () => {
  return null;
}

const item: MapNullable<MyInterface> = {};
item.member1 = myFunction(); // member1?: number | null | undefined

MapNullable iterates through all properties. If property is optional, it just extend this property with one more type - null, if property is not optional it leaves it as is.

I understand it is not the best solution, but at least it can help you with migration. Once, you migrate, you can make your types more robust and get rid of MapNullable interface.

MapNullable is not the best name for type, but still better than Foo or Bar

I agree with @jcalz, I can't imagine other way to handle undefined|null in other way

UPDATE

It looks like your code works without error in TS playground. Please see here

I have disabled strictNullChecks. There is no error.

You should explicitly set return type of your function.

const myFunction = ():null => {
  return null;
}

TS version: 4.0.2