Easier destructuring with type annotations on binding patterns
See original GitHub issueSearch Terms
type inference destructuring syntax conflict
Suggestion
It’s currently not possible to destructure a value in Typescript and provide types for each of the values due to the syntax clash with destructuring and renaming at the same time. You can see exactly this issue in the Typescript FAQs at: https://github.com/Microsoft/TypeScript/wiki/FAQ#why-cant-i-use-x-in-the-destructuring-function-f-x-number------
This is frustrating when programming in React where it’s very common to see this pattern:
const MyComponent = ({ a, b }) => {
// ...
}
But in Typescript a and b are untyped (inferred to have type any
) and type annotation must be added (either to aid in type safety or to avoid compiler errors, depending on the state of the user’s strict flags). To add the correct type annotation it feels natural to write:
const MyComponent = ({ a : string, b : number }) => {
// ...
}
but that’s not what the user thinks due to the aforementioned syntax clash. The only valid syntax in Typescript is actually this:
const MyComponent = ({ a, b } : { a : string, b : number }) => {
// ...
}
Which is very strange to write and difficult to read when the object has more than two parameters or the parameters have longer names. Also the value names have been duplicated – once in the destructuring and once in the type annotation.
I suggest we allow some other symbol (my current thinking is a double colon) to make the syntax unambiguous in this specific scenario:
const MyComponent = ({ a :: string, b :: number }) => {
// ...
}
Although this is really the only place it would be used, for the sake of consistency, I think is should be allowed everywhere:
const a :: string = "";
const b :: number = 1;
Use Cases
It would allow for type-safe destructuring of values where the type cannot be inferred by the compiler (such as function parameters).
Examples
A good example of the sort of React components I’m talking about (and one of the first Google results for React Functional Components) can be found at https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc. We can use my proposed syntax in the functional component definition:
import React from 'react'
const HelloWorld = ({name :: string}) => {
const sayHi = (event) => {
alert(`Hi ${name}`)
}
return (
<div>
<a href="#"
onclick={sayHi}>Say Hi</a>
</div>
)
}
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.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:177
- Comments:71 (9 by maintainers)
Top GitHub Comments
I agree it’s a duplicate but it really does suck. We should try again.
Actually the more I think about
::
the more I like it 😁, but with a slightly different meaning. Let’s not consider::
as a new way to introduce a type annotation, but rather an empty rename.I personally think it flows nicely. The first
:
always introduces a name binding, which can be empty, the second:
always introduces a type annotation, and since a new:
not valid here in ES it would not be ambiguous.Would work decently with objects too: