Skip to content

Commit

Permalink
fix #3033: mapped type parameters can be keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Apr 1, 2023
1 parent b2b8978 commit 9fbf1fd
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## Unreleased

* Allow keywords as type parameter names in mapped types ([#3033](https://github.com/evanw/esbuild/issues/3033))

TypeScript allows type keywords to be used as parameter names in mapped types. Previously esbuild incorrectly treated this as an error. Code that does this is now supported:

```ts
type Foo = 'a' | 'b' | 'c'
type A = { [keyof in Foo]: number }
type B = { [infer in Foo]: number }
type C = { [readonly in Foo]: number }
```
## 0.17.14
* Allow the TypeScript 5.0 `const` modifier in object type declarations ([#3021](https://github.com/evanw/esbuild/issues/3021))
Expand Down
6 changes: 4 additions & 2 deletions internal/js_parser/ts_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,12 @@ loop:
// Valid:
// "[keyof: string]"
// "{[keyof: string]: number}"
// "{[keyof in string]: number}"
//
// Invalid:
// "A extends B ? keyof : string"
//
if p.lexer.Token != js_lexer.TColon || (!flags.has(isIndexSignatureFlag) && !flags.has(allowTupleLabelsFlag)) {
if (p.lexer.Token != js_lexer.TColon && p.lexer.Token != js_lexer.TIn) || (!flags.has(isIndexSignatureFlag) && !flags.has(allowTupleLabelsFlag)) {
p.skipTypeScriptType(js_ast.LPrefix)
}
break loop
Expand All @@ -329,7 +330,8 @@ loop:
// "type Foo = Bar extends [infer T] ? T : null"
// "type Foo = Bar extends [infer T extends string] ? T : null"
// "type Foo = Bar extends [infer T extends string ? infer T : never] ? T : null"
if p.lexer.Token != js_lexer.TColon || (!flags.has(isIndexSignatureFlag) && !flags.has(allowTupleLabelsFlag)) {
// "type Foo = { [infer in Bar]: number }"
if (p.lexer.Token != js_lexer.TColon && p.lexer.Token != js_lexer.TIn) || (!flags.has(isIndexSignatureFlag) && !flags.has(allowTupleLabelsFlag)) {
p.lexer.Expect(js_lexer.TIdentifier)
if p.lexer.Token == js_lexer.TExtends {
p.trySkipTypeScriptConstraintOfInferTypeWithBacktracking(flags)
Expand Down
6 changes: 6 additions & 0 deletions internal/js_parser/ts_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ func TestTSTypes(t *testing.T) {
expectPrintedTS(t, "type Foo<T> = {readonly [P in keyof T]: T[P]}", "")
expectPrintedTS(t, "type Foo<T> = {-readonly [P in keyof T]: T[P]}", "")
expectPrintedTS(t, "type Foo<T> = {+readonly [P in keyof T]: T[P]}", "")
expectPrintedTS(t, "type Foo<T> = {[infer in T]?: Foo}", "")
expectPrintedTS(t, "type Foo<T> = {[keyof in T]?: Foo}", "")
expectPrintedTS(t, "type Foo<T> = {[asserts in T]?: Foo}", "")
expectPrintedTS(t, "type Foo<T> = {[abstract in T]?: Foo}", "")
expectPrintedTS(t, "type Foo<T> = {[readonly in T]?: Foo}", "")
expectPrintedTS(t, "type Foo<T> = {[satisfies in T]?: Foo}", "")
expectPrintedTS(t, "let x: number! = y", "let x = y;\n")
expectPrintedTS(t, "let x: number \n !y", "let x;\n!y;\n")
expectPrintedTS(t, "const x: unique = y", "const x = y;\n")
Expand Down

0 comments on commit 9fbf1fd

Please sign in to comment.