-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Do not widen literal types when emitting declarations #55445
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
//// [tests/cases/compiler/declarationEmitBindingPatterns2.ts] //// | ||
|
||
//// [declarationEmitBindingPatterns2.ts] | ||
// https://github.com/microsoft/TypeScript/issues/55439 | ||
|
||
function foo(): { y: 1 } { | ||
return { y: 1 }; | ||
} | ||
|
||
export const { y = 0 } = foo(); | ||
|
||
|
||
|
||
|
||
//// [declarationEmitBindingPatterns2.d.ts] | ||
export declare const y: 1 | 0; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
//// [tests/cases/compiler/declarationEmitBindingPatterns2.ts] //// | ||
|
||
=== declarationEmitBindingPatterns2.ts === | ||
// https://github.com/microsoft/TypeScript/issues/55439 | ||
|
||
function foo(): { y: 1 } { | ||
>foo : Symbol(foo, Decl(declarationEmitBindingPatterns2.ts, 0, 0)) | ||
>y : Symbol(y, Decl(declarationEmitBindingPatterns2.ts, 2, 17)) | ||
|
||
return { y: 1 }; | ||
>y : Symbol(y, Decl(declarationEmitBindingPatterns2.ts, 3, 10)) | ||
} | ||
|
||
export const { y = 0 } = foo(); | ||
>y : Symbol(y, Decl(declarationEmitBindingPatterns2.ts, 6, 14)) | ||
>foo : Symbol(foo, Decl(declarationEmitBindingPatterns2.ts, 0, 0)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
//// [tests/cases/compiler/declarationEmitBindingPatterns2.ts] //// | ||
|
||
=== declarationEmitBindingPatterns2.ts === | ||
// https://github.com/microsoft/TypeScript/issues/55439 | ||
|
||
function foo(): { y: 1 } { | ||
>foo : () => { y: 1;} | ||
>y : 1 | ||
|
||
return { y: 1 }; | ||
>{ y: 1 } : { y: 1; } | ||
>y : 1 | ||
>1 : 1 | ||
} | ||
|
||
export const { y = 0 } = foo(); | ||
>y : 1 | 0 | ||
>0 : 0 | ||
>foo() : { y: 1; } | ||
>foo : () => { y: 1; } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,7 +82,7 @@ declare function fs(x: string): void; | |
declare function fx(f: (x: "def") => void): void; | ||
declare const x1: (x: string) => void; | ||
declare const x2 = "abc"; | ||
declare const x3: string; | ||
declare const x3: "def" | "abc"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand that there is this hidden widening thing encoded in the type and that it actually might widen when assigned to a mutable declaration. I think though that most people are not aware of this and it's more surprising that a type widened in the emitted declaration - people never audit them until something goes wrong. The current behavior is also surprising in some cases. Let's expand on this very case here: declare function f3<T>(obj: T, f1: (x: T) => void, f2: (f: (x: T) => void) => void): T;
declare function fo(x: Object): void;
declare function fx(f: (x: "def") => void): void;
const x3 = f3("abc", fo, fx); // "abc" | "def"
let other: typeof x3 = x3
other = 'other' // error As we can see we can't assign declare const x3: string;
declare let other: typeof x3; It means that in practice we can end up with an error locally that wouldn't get reported if the same code would get used through the declaration file. I find that problematic. The same could be said about the widening thing because "locally" an assignment would widen but if we change the declaration emit then the equivalent assignment would not widen since the widening behavior can't be encoded in the declaration file. I think though that's a smaller problem and a better tradeoff. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Correct! And in most cases in declaration emit, the way we handle this is by preserving the literal initializer, rather than serializing a type annotation - that way the declaration has the same widening behavior as the original source. Eg, if you write export const six = 6; that is also, verbatim, the declaration emit. Unfortunately, right now this only covers simple cases of widening types - a heritage from our older, much simpler string-based declaration emitter. IMO, rather than making an equally incorrect declaration in the other direction (preserving the literal types, rather than the widened type), we need to, once again, preserve the initializer to preserve the literal-widening behavior. In this case, that should mean making initializers with the same behavior. Take the original issue: function foo(): {y: 1} {
return { y: 1 }
}
export const { y = 0 } = foo(); If we serialize it to declare const _expr: {y: 1};
export declare const { y = 0 } = _expr;
|
||
declare const x4: Func<string>; | ||
declare const never: never; | ||
declare const x10: string; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// @strict: true | ||
// @declaration: true | ||
// @emitDeclarationOnly: true | ||
|
||
// https://github.com/microsoft/TypeScript/issues/55439 | ||
|
||
function foo(): { y: 1 } { | ||
return { y: 1 }; | ||
} | ||
|
||
export const { y = 0 } = foo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly I think this case came up during our talks about
isolatedDeclarations
. The code for these two is:@RyanCavanaugh @DanielRosenwasser
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I just realized who reported the bug, it is directly related!