Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'Nullable' built-in utility type #39522

Closed
5 tasks done
wessberg opened this issue Jul 9, 2020 · 5 comments
Closed
5 tasks done

Add 'Nullable' built-in utility type #39522

wessberg opened this issue Jul 9, 2020 · 5 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript

Comments

@wessberg
Copy link

wessberg commented Jul 9, 2020

I've made a PR

Search Terms

Nullable

Suggestion

TypeScript already comes with a NonNullable type, defined in lib.es5.d.ts:

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T extends null | undefined ? never : T;

I propose that its inverse, Nullable, is added to the built-in type utilities.

I'm aware that your general position in terms of built-in type utilities is that you don't extend them unless strictly necessary, but I do think this is an important addition for the following reason:

The built-in type utilities generally offer inverse types. For example, Partial is the inverse of Required. And, Pick is the inverse of Omit. Because of this, to me it naturally follows that NonNullable should have an inverse called Nullable.

Use Cases

For the following examples, nullable is defined as null or undefined, thereby following TypeScripts definition from the NonNullable utility type.

A few examples that comes to mind:

  • Required keys with nullable values.
  • Function arguments that may have a nullable value.

Additionally, it may help with simplifying built-in type definitions:

For example in lib.es5.d.ts, the catch and then declarations for the Promise interface can be simplified:

interface Promise<T> {
    then<TResult1 = T, TResult2 = never>(onfulfilled?: Nullable<(value: T) => TResult1 | PromiseLike<TResult1>>, onrejected?: Nullable<(reason: any) => TResult2 | PromiseLike<TResult2>>): Promise<TResult1 | TResult2>;
    catch<TResult = never>(onrejected?: Nullable<(reason: any) => TResult | PromiseLike<TResult>>): Promise<T | TResult>;
}

There are several types, particularly in lib.dom.d.ts that could also be simplified by leveraging the Nullable type.

Examples

As part of an InterfaceDeclaration:

interface Foo {
    prop: Nullable<string>;
}

As a optional parameter to a function that may also accept null:

function validateUserInput (text: Nullable<string>): void {}

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@RyanCavanaugh RyanCavanaugh added Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript labels Jul 9, 2020
@RyanCavanaugh
Copy link
Member

We've opted to not include utility type aliases in the lib unless they're required for declaration emit purposes

@wessberg
Copy link
Author

wessberg commented Jul 9, 2020

I do realize that this is your stance, and I also address it in the issue text and provide arguments as to why I think this should be an exception to that general rule (inconsistency with existing built-in types that have inverses). The primary goal of this issue is to increase consistency, not new functionality:

I'm aware that your general position in terms of built-in type utilities is that you don't extend them unless strictly necessary, but I do think this is an important addition for the following reason:

The built-in type utilities generally offer inverse types. For example, Partial is the inverse of Required. And, Pick is the inverse of Omit. Because of this, to me it naturally follows that NonNullable should have an inverse called Nullable.

@RyanCavanaugh
Copy link
Member

Consistency is a proxy measure, not an endgoal. We don't do things just to increase consistency; we do them to improve developer's experiences. What we've heard from users is that they don't like it when we needlessly add new global types because a) it causes conflicts with theirs and b) we don't always pick the same definition that they were using.

@wessberg
Copy link
Author

wessberg commented Jul 10, 2020

Alright, that's fair. Again, I know this is your stance and have also seen this reasoning behind declining other proposals for built-in types, but I thought this was different in that it felt like a needed omission as a companion to NonNullable, hence the issue and PR. But I'll go ahead and close it.

@Expertus777
Copy link

Consistency is a proxy measure, not an endgoal. We don't do things just to increase consistency; we do them to improve developer's experiences. What we've heard from users is that they don't like it when we needlessly add new global types because a) it causes conflicts with theirs and b) we don't always pick the same definition that they were using.

Probably you should reserve some keywords as JS do.

@microsoft microsoft locked as resolved and limited conversation to collaborators Aug 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants