Proposal: Supplementing Implicit Types
See original GitHub issueIn a type expression, I would like to be able to extend the implicitly known type of a value with specific type information.
The purpose is to get the most from the implicit type information and suplement it when some type information is missing.
Also, this will pull typescript even closer to ES6 by allowing common ES6 patterns like argument destructuring which results in the any type (where the type cannot currently be specified).
Syntax
// Like normal type information
const { req, opt = '', def = 'DEFAULT' }: { req: string, opt?: string, def?: string } = values;
// But 'extends' implicit typing
const { req, opt = '', def = 'DEFAULT' }: extends { req: string } = values;
The extends keyword would only modify the type information for the part of the type expression that was specified.
Useful Cases
Argument Destructuring with Type Information
Refer to: https://github.com/Microsoft/TypeScript/issues/7576#issuecomment-198443953 And my comment there: https://github.com/Microsoft/TypeScript/issues/7576#issuecomment-340190459
Full Typing (Absolutely no advantage from implicit type information)
export const Fun = ({ req, opt = '', def = 'DEFAULT' }: { req: string, opt?: string, def?: string }) => {
// ...
};
Current Best Solution
This uses Pure Implicit Typing, but it requires a default parameter that allows an unintended invalid call.
export const Fun = ({ req, opt = '', def = 'DEFAULT' } = { req: '' }) => {
// GOOD: All variables are implicitly typed
// ...
};
export const Fun_Call = () => {
// BAD: It is possible to call without arguments (i.e. pseudo-required)
Fun();
// GOOD: But if any object is given, it works right
Fun({ req: '' });
};
With Extends
export const Fun_extends = ({ req, opt = '', def = 'DEFAULT' }: extends { req: string }) => {
// ...
};
export const Fun_Call = () => {
// GOOD: This is not allowed
// Fun();
// GOOD: An object must be given with the correct typing
Fun({ req: '' });
};
Extending Return Values
Current Best Solution
// Complex Objects:
const ComplexReturn = () => { return { a: 'a', b: 'b', c: 'c' }; };
const obj = ComplexReturn();
const objWithD_typeofWithObject = obj as typeof obj & { d: string };
With Extends
// Complex Objects:
const ComplexReturn = () => { return { a: 'a', b: 'b', c: 'c' }; };
const objWithD_extends = ComplexReturn() as extends { d: string };
Checklist
Syntactic
- What is the grammar of this feature?
- ‘extends’ at the beginning of type expression like ‘typeof’ or ‘keyof’
- Are there any implications for JavaScript back-compat? If so, are they sufficiently mitigated?
- No
- Does this syntax interfere with ES6 or plausible ES7 changes?
- No
Semantic
- What is an error under the proposed feature? Show many examples of both errors and non-errors
- The keyword would work in any type expression, just like ‘keyof’
- How does the feature impact subtype, supertype, identity, and assignability relationships?
- For inheritance, it could be used to extend class members from their supertype
- How does the feature interact with generics?
- It would not change how the keyword is used with generics
Emit
- What are the effects of this feature on JavaScript emit? Be specific; show examples
- This is pure typing, it would be removed from runtime emit
- Does this emit correctly in the presence of variables of type ‘any’? Features cannot rely on runtime type information
- N/A
- What are the impacts to declaration file (.d.ts) emit?
- The keyword would need to by included in the declaration file typing information
- Does this feature play well with external modules?
- Yes
Compatibility
- Is this a breaking change from the 1.0 compiler? Changes of this nature require strong justification
- Unknown
- Is this a breaking change from JavaScript behavior? TypeScript does not alter JavaScript expression semantics, so the answer here must be “no”
- no
- Is this an incompatible implementation of a future JavaScript (i.e. ES6/ES7/later) feature?
- no
Other
- Can the feature be implemented without negatively affecting compiler performance?
- Yes
- What impact does it have on tooling scenarios, such as member completion and signature help in editors?
- It will provide a new type for that type expression
Issue Analytics
- State:
- Created 6 years ago
- Reactions:3
- Comments:7 (1 by maintainers)
Top GitHub Comments
This is definitely the most interesting solution to the destructuring arguments typing problem that I’ve seen proposed.
Ah, yeah I think ECMAscript destructured renaming is the worst design decision I have seen in modern languange design (especially when they knew very well that this would fly in the face of TypeScript).
Like what were they thinking…
‘’’ // Since everybody understands this well const x = { a : “value”, b: “value”, };
// And this is clear const {a,b} = x;
// And we need Default values const { a, b, c=42 } = x;
// What about renaming?
// This would be too easy const { a2:a, b2:b} = x;
// Oh, I know, let’s just reverse them because it makes sense - after all we have exactly no examples in the entire languange where a value assignment flows from left to right. So let’s just go in reverse from expected order for no good reason at all. const { a:a2, b:b2} = x;
// Not only will this send a clear sign to TypeScript that we can do whatever we feel like, it will bring back the good old days when everyone made fun of horrible JavaScript design decisions. ‘’’
I don’t think that was the exact thought process, but I just don’t get it.