Repository navigation
Inline type annotations for destructured properties using angle bracket syntax #58633
Description
🔍 Search Terms
inline type annotations, type annotations, destructuring annotations, destructuring, property annotations, parameter destructuring,
✅ Viability Checklist
- 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 isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion
I've observed a lot of discussion around the verbosity/duplication involved when providing type annotations for destructured object properties (particularly re-ignited by this Svelte issue), which prompted me to wonder if this could be resolved with additional syntax being introduced to TypeScript.
The proposal suggests introducing new syntax for adding inline type annotations using angle brackets <T> within destructuring assignments that can be added immediately after the property keys, along with a new optional modifier keyword to indicate a property as optional.
e.g. this
// before
function fetchData({
url,
method = "GET",
timeout = 0
}: {
url: string;
method?: string;
timeout?: number;
}) {
console.log(`Fetching data from ${url} with method ${method} and timeout ${timeout}`);
}
// after
function fetchData({
url<string>,
method<optional string> = "GET",
timeout<optional number> = 0
}) {
console.log(`Fetching data from ${url} with method ${method} and timeout ${timeout}`);
}For completeness (though far less valuable), this could probably also support providing annotations in array destructuring assignments as well. e.g.
// before
function processCoordinates([x, y, z]: [number, number, number]) {
console.log(`Coordinates are x: ${x}, y: ${y}, z: ${z}`);
}
// after
function processCoordinates([x<number>, y<number>, z<number>]) {
console.log(`Coordinates are x: ${x}, y: ${y}, z: ${z}`);
}Advantages:
- Readability when destructuring is improved as the types are colocated directly next to each of the destructured properties.
- Less verbose/redundancy as you don't have to declare destructured properties twice.
Drawbacks:
- The angle bracket syntax might introduce more confusion to understanding TypeScript syntax, given it is already being used for both generics and type casting.
- This is a non-backwards compatible breaking change to TypeScript.
Other considerations:
- Should the
optionalmodifier keyword also work inside of object literal types. - Could a
?be used instead of the newoptionalmodifier inside/outside of the brackets (e.g.url?<string>orurl<string?>). Would probably be more familiar to the way optional properties are defined now, but it might get confusing whether?is part of the property name in the first example, or part of conditional logic in the second.
📃 Motivating Example
Drawing inspiration from the Svelte $props issue linked above, a React equivalent example might look like:
// before
const Button = ({
label,
size = 'medium',
onClick,
disabled = false
}: {
label: string;
size?: 'small' | 'medium' | 'large';
onClick?: () => void;
disabled?: boolean;
}) => {
return (
<button
className={`btn ${size}`}
onClick={onClick}
disabled={disabled}
>
{label}
</button>
);
};
// after
const Button = ({
label<string>,
size<optional 'small' | 'medium' | 'large'> = 'medium',
onClick<optional () => void>,
disabled<optional boolean> = false
}) => {
return (
<button
className={`btn ${size}`}
onClick={onClick}
disabled={disabled}
>
{label}
</button>
);
};💻 Use Cases
- What do you want to use this for?
Reducing duplication whenever needing to do destructuring assignments with type annotations. In particular it will solve the Svelte issue linked above, but applies anywhere you use destructuring and type annotations that you commonly see with function arguments.
- What shortcomings exist with current approaches?
As discussed above already, it's unnecessarily verbose and duplicative, and prevents the colocation of types where you probably want to see them.
- What workarounds are you using in the meantime?
Move the type declarations for destructured function params above/outside of the destructuring assignment, but this isn't actually addressing the problems solved by the new syntax.
Activity
whzx5byb commentedon May 23, 2024
Related: #29526.
Not-Jayden commentedon May 23, 2024
Thanks whzx5byb, will close as a duplicate
fatcerberus commentedon May 23, 2024
Wow that comment thread turned into a trainwreck at the end there. It seems to have completely devolved to “why you just shouldn’t use destructuring at all, and then you won’t need this feature” which is just… not productive at all