-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Change default inference from arrays to tuples and primitives to literals #38831
Comments
Issue #38727 is related |
Also related: #16896 |
It looks like you want
|
Yes, I use TypeScript based type check for jsdoc type declarations in .js files and I can't use |
See #32758 |
@RyanCavanaugh no, #32758 is not my proposal. They want, for example, use const a = [1, 2, 3] or use readonly modifier for object properties by default. I'm asking for a type checker mode where types will be inferred as 'literal' (use literals instead of basic types) as possible. // Got: Array<number>
// Proposal: [1, 2]
const a = [1, 2] declare function b<T extends Array<unknown>>(...args: T): T
// Got: [number, number, number]
// Proposal: [1, 2, 3]
const c = b(1, 2, 3) // Got: { data: number }
// Proposal: { data: 2 }
const b = { data: 2 } etc |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
@RyanCavanaugh please reopen this issue. It is not duplicate. |
@awerlogus I don't see any measurable difference between these issues. Certainly we would implement that flag as applying equally to both arrays and objects - are you saying we would need two different flags, one for arrays, one for objects? |
@RyanCavanaugh as I said 2 times before, I don't ask you to add a compiler mode, where all types will be readonly. My proposal is a mode to make type checker prefer inferring entities as literals over basic types when it's possible. Using number literals over Examples are available here: #38831 (comment) |
I guess I'd like to understand what you think isn't effectively read-only about the type |
I think, and correct me if I'm wrong @awerlogus , that you essentially want a mode where every expression has |
@jgbpercy the expression |
@RyanCavanaugh I didn't say that we should or should not mark tuples or objects as const a: [1, 2] = [1, 2]
// Legal
a.push(1)
// [1, 2]
const b = a Readonly tuple will not allow it const c: readonly [1, 2] = [1, 2]
// Error
c.push(1) So, the question becomes: should we have any access to mutating array methods in case of mutable tuples? Except for this, tuples and Almost the same problems with objects: const a: { readonly data: 2 } = { data: 2 }
// Should not be valid
Object.defineProperty(a, 'data', { value: 3 })
const b: { data: 2 } = { data: 2 }
// Should not be valid too
Object.defineProperty(b, 'data', { value: 3 }) It should be fixed, I think. If we will need some mutable object, it will be not possible to get it from I think, good programming language should help developers write the better code. And in the good code all data types and its transformations are managed by functions. There're some types that expected to be passed into and returned from functions. Types of variables and constants should be inferred as narrow as possible to may be correctly passed to as many functions as possible. Let me show an example: declare function a<T extends { readonly data: number }>(arg: T): T['data']
declare function b<T extends { readonly data: 1 | 2 }>(arg: T): T['data']
// Now: { data: number }
// Proposed: { data: 2 }
const c = { data: 2 } Now variable p.s. There's no |
@awerlogus would you consider editting the description of the issue, adding this info? I think it answers all questions about your proposal. I also agree it may be nice for them to be two separate flags. Also may consider renaming suggestion to "implicit as-const for type narrowing flag" or "--strict-type-narrowing flag"? Question: are there cases in which this flag could be harmful? Also: now that records and tuples are stage 2, could this (or even both) issues be (partially) addressed by that proposal instead, with no (or little) change to TS? |
All this conversation is the issue description. So info described in that comment already exists here. I always read comments under issues I'm interested. If someone doesn't do that is means they're not interested enough.
If you prefer working with mutability it can make you cast types to more general ones too often. For example cast Also even currently when we modelling function overloading without overloading (because it's designed bad) we may have some problems with types inferred too literally. For example let's try to rewrite this function function add(a: number, b: number): number
function add(a: bigint, b: bigint): bigint
function add(a: any, b: any) { return a + b } It will look like function add<P extends [a: number, b: number] | [a: bigint, b: bigint]>(...data: P): P[0] {
return data[0] + data[1]
} If we call it, we will get return type equal to the first argument because // Got: 1
const a = add(1, 2) So it makes us generalize return type of the function and use I think such cases of generalization necessity will occur more often when using the flag. This example also produces an error: function add<P extends [a: number, b: number] | [a: bigint, b: bigint]>(...data: P): P[0] extends bigint ? bigint : number {
// Operator '+' cannot be applied to types 'number | bigint' and 'number | bigint'.ts(2365)
return data[0] + data[1]
} @RyanCavanaugh do we have an issue describing the error above?
It's a good question. How about mutable objects containing enums? This example will still not work after adding records and tuples function test(a: { data: 1 | 2 }) { return a }
const a = { data: 2 }
// Types of property 'data' are incompatible.
// Type 'number' is not assignable to type '2'.ts(2345)
const b = test(a) |
I have to say that I would definitely like something like this to exist. My use case involves my most common use of typing functions, namely type Example: function getOtherData(from:T): R { ... }
const sourceArray: T[] = ...;
...
sourceArray
.map(elem => [elem, getOtherData(elem)]
.map([elem, other] => { ... }); // here both `elem` and `other` have type `T | R` |
"make type checker infer types as narrow as possible" seems like the idea of immutability. And is discussed at least in one other issue #32758 .
I cannot see the difference between the 'literal' proposed by @awerlogus , and the literal type from 'readonly'. Could you explain more? I still think this issue can be closed without further information (note that it has been 2 years without reply). @RyanCavanaugh @typescript-bot |
I am working on functional project now and I'm getting a lot of errors related to too wide type inference for values. It looks like
There're really many errors like this, and the main problem is that you can convert type A to type B, but not vice versa.
So, I ask you to add a new compiler option (to not break existing code) that will make type checker infer types as narrow as possible. It will be very helpful for functional programming.
The text was updated successfully, but these errors were encountered: