Inferred constructable types
See original GitHub issueSuggestion
This issue proposes constructable inferred types. It solves this:
// Ability to construct objects without errors
var obj = {a:1}
obj.b = 2 // Error: typescript presumes that obj is meant to be the finished type {a:1} - It isn't.
obj.c = 3 // Error
Proposed syntax which says “This is not a finished type. This is a type under construction.”;
var obj : unfinished
var obj : constructable
var obj : inferred
Then:
var obj = {a:1} as unfinished
obj.b = 2
obj.c = 3
obj // {a:1, b:2, c:3} - OK
var something1 : unfinished
something1 = 1
something1 = "a"
something1 // number | string
var something2 : unfinished
something2 = new myClass
something2.newProp = 1
something2 // myClass & {newProp: 1}
var something3 : unfinished = {a: 1}
something3.b = 2
something3 = "a" // Compile Error! Primitives and objects are incompatible ? - No.
something3 = "a" // Yes: {a: 1, b: 2} | "a"
something3 // is the subtype of; {a: number, b: number} | string
something3 // and should be assignable to any type that that has this form or subform
var something4 : unfinished = {a: 1}
something4 = new myClass
something4.newProp = 2
something4 = {c: 3}
something4 = [1]
something4 = "a"
something4 = false
something4 // [1] & {a: 1, c: 3, newProp: 2} & myClass | "a" | false
something4 // which is the subtype of: Array<number> & {a: number, c: number, newProp: number} & myClass | string | boolean
// Inference should always work without errors.
// This allows turning a ".js" file into a ".ts" file with 'fewer' issues if "unfinished" is the default for the file.
// If "unfinished" is the default then the "unfinished" typehint is not needed. That must always be the case in "js" files.
// In a ".js" file:
function getValue(x) {
var o = {}
o.a = 1
if(x == 2) o.b = 2
else if(x == 3) o = "c"
else o = x.else
return o
}
var val = getValue(window.x)
val // {a: 1, b?: 2} | "c" | any
Basically, all object types are combined “&”, all primitives are added as alternatives “|”.
An inferred constructable type also means, and the “unfinished” typehilt also says: “The code defines the schema of the type”.
So you don’t need an interface or need to keep an interface that you have laying around somewhere in sync with the code that defines it. You can reference the type via type t = typeof theVariableThatHoldsIt
.
Current Workaround: Typescript already has the ability to infer a constructed type, but only with the identifier of a function statement and without narrowing. This can be expanded to all variables.
function obj() {}
obj.toJSON = ()=>Object.assign({}, obj) // if serialization is ever wanted - Problem: the "toJSON" property is added.
obj.a = 1
if(x) obj.b = 2
obj // function obj(): { (): void; toJSON(): ...; a: number; b: number; }
🔍 Search Terms
inferred types, constructable type, extendable object
✅ 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.
–>
Issue Analytics
- State:
- Created 2 years ago
- Reactions:4
- Comments:12 (3 by maintainers)
I’m still learning the irks & quirks of typescript - and btw, I just figured out that type construction for objects is already implemented to some degree - but only within
.js
files! I have also figured out that you can import types into.js
files, not just variables of a type.The import is dropped by the bundler. JSdocs offer additional ways to define types inside comments. I don’t know about you guys but I’d rather have useful type annotations in comments than
@ts-ignore
all over the place.So as it turns out, there is absolutely no reason at all to work with
.ts
files.You lose out on nothing. You get all the productivity gains of api descriptions and auto completion that types are meant to provide - and you avoid all the productivity obstacles of typescript. Like #46941, #47560, this #47559, … and countless other issues + dealing with workaround after workaround after workaround. You also avoid committing your codebase to a syntax that may change, - or exposing yourself to a situation where walking back or migrating to a different typing system in the future with different development tools becomes impossible.
As I’ve mentioned in #46941. A typing system is not supposed to “validate” an entire file and meddle with things that are outside of its area of responsibility. It is supposed to simply provide helpful hints where they are wanted. Nothing more. In that respect typescript’s philosophy is utterly flawed.
If you just want helpful hints instead of validation, then JSDoc is the right fit for you!