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

feat: downlevel type in index signatures #84

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,25 @@ type T = [/** foo */ number, /** bar */ string];
The downlevel semantics are exactly the same as the original, but
the TypeScript language service won't be able to show the member names.

### `{ [key: T]: A }` (4.4)

Typescript 4.4 supports template literals as index signature types:

```ts
type O = { [key: `ak${string}`]: A };
```

becomes

```ts
type O = { [key: string]: A };
```

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a Semantics section. Specifically, the transformation as written makes sense for cases where

  1. the type is a template literal
  2. the type is reference to a template literal
    because x${number}y -> string (for example) is more permissive.

I'm not sure it makes sense for the following types that also work in 4.4:

  1. symbol
  2. a reference to symbol
  3. unions of string, symbol, number or template literals.
  4. a reference to unions of string, symbol, number or template literals.

cases (2), (4) and (6) are syntactically ambiguous, so I don't think they can be downlevelled with this tool.
(3) can't be downlevelled at all.
(5) can be downlevelled to multiple index signatures if the symbol isn't in the union.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it to satisfy only the first case.

Regarding making it compatible with the second case, can we add a flag for "unsafe" transformations or allow transformations provided by user?

#### Semantics

The downlevel d.ts will be less strict because an index signature would
have a more general type (`string`) instead of the original template literal type.

### `in out T` (4.7)

Typescript 4.7 supports variance annotations on type parameter declarations:
Expand Down
3 changes: 3 additions & 0 deletions baselines/reference/ts3.4/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ export declare const foo: {
export type IR = IteratorResult<number>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts3.5/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ export declare const foo: {
export type IR = IteratorResult<number>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts3.6/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts3.7/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts3.8/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts3.9/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.0/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = string;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.1/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.2/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.3/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: string]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.4/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: `${string}abc${string}`]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.5/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: `${string}abc${string}`]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.6/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: `${string}abc${string}`]: number;
};
3 changes: 3 additions & 0 deletions baselines/reference/ts4.7/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ export declare const foo: {
export type IR = IteratorResult<number, string>;
/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;
export type TTemplateLiteralIndexSignature = {
[key: `${string}abc${string}`]: number;
};
20 changes: 20 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,26 @@ function doTransform(checker, targetVersion, k) {
ts.unescapeLeadingUnderscores(member.name.escapedText),
/*hasTrailingNewline*/ false
);
} else if (
semver.lt(targetVersion, "4.4.0") &&
ts.isIndexSignatureDeclaration(n) &&
ts.SyntaxKind.TemplateLiteralType === n.parameters[0].type.kind
) {
const [p] = n.parameters;
return ts.factory.createIndexSignature(
n.modifiers,
[
ts.factory.createParameterDeclaration(
p.modifiers,
p.dotDotDotToken,
p.name,
p.questionToken,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
p.initializer
)
],
n.type
);
} else if (semver.lt(targetVersion, "4.7.0") && ts.isTypeParameterDeclaration(n)) {
return ts.factory.createTypeParameterDeclaration(
n.modifiers?.filter(
Expand Down
2 changes: 2 additions & 0 deletions test/test.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ export type IR = IteratorResult<number, string>;

/** Template Literal - supported since 4.1 < should be StringKeyword */
export type TTemplateLiteral = `${string}abc${string}`;

export type TTemplateLiteralIndexSignature = { [key: `${string}abc${string}`]: number }