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

Optional types syntax (2 defs: w/ type and w/ inline definition) - closed prematurely #51883

Closed
5 tasks done
brandonmcconnell opened this issue Dec 13, 2022 · 4 comments
Closed
5 tasks done
Labels
Duplicate An existing issue was already created

Comments

@brandonmcconnell
Copy link

Suggestion

🔍 Search Terms

type optional syntax variable definition

✅ Viability 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, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

I think it could be very useful to be able to declare optional types in TypeScript in a more clear and consise way. This proposal is two-fold— one syntax for defining a type and one syntax for inline typing on a variable.

  • For type usage, I propose a shorthand syntax TypeName ?= Type which would match for the specified type or undefined, where the ?= indicates that it is optional and can match either the specified type or undefined.
  • For inline variable usage, I propose a shorthand syntax let variableName ?: Type which would type the variable as the specified type or undefined, where the ?: indicates that the variable is optional and can either be of the specified type or undefined.

This syntax would provide a more concise and readable way to create optional variables, as opposed to using the | undefined syntax which can be somewhat unwieldy, especially when creating a handful of variables you want toi be optional within a framework.

This would make it easier to clearly communicate the intended use of a variable to other developers reading your code.

📃 Motivating Example

You could use the optional type syntax to create an optional type and then use it like this:

type Name ?= string;

let myName: Name;

// myName is now optional and can either be a string or undefined

You could use the optional inline variable syntax to create an optional type on the variable like this:

let myName?: string;

// myName is now optional and can either be a string or undefined

…but what if someone uses both?

It's plausible that in some cases, a user may use the optional inline syntax using a type that already uses the optional type syntax, or create unions or intersections using some optional and other non-optional types.

For union types, that could look something like this:

type Name ?= string;
type Age = number;

// assume `personalDetail` can be a name or age
let personalDetail: Name | Age;

// myName is now optional and can either be a string or undefined

In these cases, I think it woulkd make the most the most sense just to let any types declared with the an optional declaration be shorthand for their same usage as Type | undefined, so in the above example, the type for personalDetail would evaluate to string | undefined | number.

For intersection types, the type would usually evaluate to never, the same that it would if union-ing with undefined, like in this example:

type Name ?= string;
type Age = number;

// assume `personalDetail` can be a name or age
let personalDetail: Name & Age;

// myName is now of type `never` as `string | undefined` does not intersect with `number`.

💻 Use Cases

Working within Svelte, for example, it's not uncommon to see TypeScript used like this when defining props:

<script lang="ts">
  export let prop1: string | undefined = undefined;
  export let prop2: number | undefined = undefined;
  export let prop3: string[] | undefined = undefined;
  export let prop4: { prop: number } | undefined = undefined;
  export let prop5: string | null | undefined = undefined;
</script>

With this proposal implemented, this block could be rewritten to the following:

<script lang="ts">
  export let prop1 ?: string;
  export let prop2 ?: number;
  export let prop3 ?: string[];
  export let prop4 ?: { prop: number };
  export let prop5 ?: string | null;
</script>

The space here would be optional, as always, so this would produce the same result:

<script lang="ts">
  export let prop1?: string;
  export let prop2?: number;
  export let prop3?: string[];
  export let prop4?: { prop: number };
  export let prop5?: string | null;
</script>
@MartinJohns
Copy link
Contributor

MartinJohns commented Dec 13, 2022

Partially a duplicate of #41901. Other suggestion is partially covered by #35577.

@DanielRosenwasser DanielRosenwasser added the Duplicate An existing issue was already created label Dec 14, 2022
@DanielRosenwasser
Copy link
Member

Appreciate the write-up, but I do think that we've discussed these before. The only thing I could see us doing to revisit binding name optionality is for the global scope (think Node's .d.ts files, or lib.*.d.ts).

@brandonmcconnell
Copy link
Author

brandonmcconnell commented Dec 14, 2022

@MartinJohns @DanielRosenwasser I haven't come across any tickets—still—that this ticket duplicates.

Looking at two seemingly related tickets—

This proposal I'm submitting here does not overlap with either of those, as this relates to top-level variables or types in a given scope, though not necessarily global.

There is no way to achieve this currently without explicitly writing | undefined = undefined. The longwinded redundancy here could use some bikeshedding, at the very least.

<script lang="ts">
  export let prop1: string | undefined = undefined;
  export let prop2: number | undefined = undefined;
  export let prop3: string[] | undefined = undefined;
  export let prop4: { prop: number } | undefined = undefined;
  export let prop5: string | null | undefined = undefined;
</script>

☝🏼🤮

<script lang="ts">
  export let prop1?: string;
  export let prop2?: number;
  export let prop3?: string[];
  export let prop4?: { prop: number };
  export let prop5?: string | null;
</script>

…though the = undefined being required might be more a matter of Svelte-specific config than TS. I'll check into that.

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@brandonmcconnell brandonmcconnell changed the title Optional types syntax (2 defs: w/ type and w/ inline definition) Optional types syntax (2 defs: w/ type and w/ inline definition) - closed prematurely Dec 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants