Skip to content
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

typeToTypeNode behavior changed for boolean literals #40203

Closed
Gerrit0 opened this issue Aug 23, 2020 · 4 comments
Closed

typeToTypeNode behavior changed for boolean literals #40203

Gerrit0 opened this issue Aug 23, 2020 · 4 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@Gerrit0
Copy link
Contributor

Gerrit0 commented Aug 23, 2020

TypeScript Version: 4.1.0-dev.20200823, 4.0.2

Search Terms:
TypeLiteral, TypeLiteralNode, boolean literal type

Code

//@ts-check
const fs = require("fs");
const ts = require("typescript");

fs.writeFileSync("test.ts", "export const x = true");

const program = ts.createProgram({ options: {}, rootNames: ["test.ts"] });
const checker = program.getTypeChecker();
const sourceFile = program.getSourceFile("test.ts");
const fileSymbol = checker.getSymbolAtLocation(sourceFile);

const xSymbol = fileSymbol.exports.values().next().value;
const xType = checker.getTypeOfSymbolAtLocation(xSymbol, sourceFile);

console.log(`${xSymbol.name}: ${checker.typeToString(xType)}`); // x: true

const xTypeNode = checker.typeToTypeNode(
  xType,
  sourceFile,
  ts.NodeBuilderFlags.IgnoreErrors
);

console.log("Literal according to type?", xType.isLiteral());
console.log("Literal according to node?", ts.isLiteralTypeNode(xTypeNode));

Expected behavior:

TS 3:

C:\Users\gtbir\Desktop\issue> node .\test.js       
x: true
Literal according to type? false
Literal according to node? false

Actual behavior:

TS 4:

C:\Users\gtbir\Desktop\issue> node .\test.js
x: true
Literal according to type? false
Literal according to node? true 

Playground Link: N/A

Related Issues: #26075 also discusses whether the intrinsic boolean types should be considered literals, the consensus there seemed to be that true and false ought to be literals... and TS 4 seems to be halfway there, which results in a confusing mismatch.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Sep 3, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.1.0 milestone Sep 3, 2020
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Dec 11, 2020
@rbuckton
Copy link
Member

When we shipped the new NodeFactory API in 4.0, we tried to clean up some confusing API designs and unsoundness. In general, it is bad for keyword tokens in "type"-space and "value"-space to overlap, as it makes it much more difficult for emit transformers to know whether they're working with the value true, vs. the type true. We were already parsing a true type as a LiteralTypeNode, but the checker was incorrectly returning a TrueKeyword or FalseKeyword token for typeToTypeNode.

Another thing we changed was that the null type is now also represented as a LiteralTypeNode, even though its not precisely a literal type. This is again because we need to avoid confusion when transformers encounter a NullKeyword token and need to be able to determine whether they are looking at the value null, vs the type null.

Regarding .isLiteral(), this function is poorly named and currently only checks whether a type is either a StringLiteral or NumericLiteral type:

isLiteral(): this is LiteralType {
return !!(this.flags & TypeFlags.StringOrNumberLiteral);
}

I would expect the output to be the following:

C:\Users\gtbir\Desktop\issue> node .\test.js
x: true
Literal according to type? false
Literal according to node? true 

The only thing that might change is if we decide to change isLiteral() to check for TypeFlags.Literal instead (widening its set of possible values), however it is unknown whether that would be a breaking change for service consumers using the API.

@RyanCavanaugh, @DanielRosenwasser any thoughts on whether isLiteral() should include other literal types like BooleanLiteral or BigIntLiteral? Seems like it may have been an oversight.

@Gerrit0
Copy link
Contributor Author

Gerrit0 commented Dec 29, 2020

This makes sense to me - I'd be happy to close this if the API breaking changes page on the wiki was updated to make a note of this.

@rbuckton
Copy link
Member

rbuckton commented Aug 3, 2021

I've updated the API Breaking Changes page in the wiki to reflect that typeToTypeNode now correctly produces a LiteralTypeNode for true and false types to match the existing parser behavior.

@rbuckton rbuckton closed this as completed Aug 3, 2021
@Gerrit0
Copy link
Contributor Author

Gerrit0 commented Aug 3, 2021

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

No branches or pull requests

4 participants