Skip to content

Commit e6ebb58

Browse files
committed
add support for heritageClauses
1 parent 59825d1 commit e6ebb58

8 files changed

+155
-9
lines changed

src/services/codefixes/convertToMappedObjectType.ts

+21-9
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ namespace ts.codefix {
4949
if (!isIndexSignatureParameterName(token)) return undefined;
5050

5151
const indexSignature = <IndexSignatureDeclaration>token.parent.parent;
52-
const container: FixableDeclaration = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : <TypeAliasDeclaration>indexSignature.parent.parent;
52+
const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : <TypeAliasDeclaration>indexSignature.parent.parent;
5353
const members = isInterfaceDeclaration(container) ? container.members : (<TypeLiteralNode>container.type).members;
5454
const otherMembers = filter(members, member => !isIndexSignatureDeclaration(member));
5555
const parameter = first(indexSignature.parameters);
@@ -63,21 +63,33 @@ namespace ts.codefix {
6363
};
6464
}
6565

66+
function getInterfaceHeritageClauses(declaration: FixableDeclaration): NodeArray<ExpressionWithTypeArguments> | undefined {
67+
if (!isInterfaceDeclaration(declaration)) return undefined;
68+
69+
const heritageClause = getHeritageClause(declaration.heritageClauses, SyntaxKind.ExtendsKeyword);
70+
return heritageClause && heritageClause.types;
71+
}
72+
6673
function createTypeAliasFromInterface(indexSignature: IndexSignatureDeclaration, declaration: FixableDeclaration, otherMembers: ReadonlyArray<TypeElement>, parameterName: Identifier, parameterType: TypeNode) {
67-
const mappedIntersectionType: TypeNode[] = [
68-
createMappedTypeNode(
69-
hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
70-
createTypeParameterDeclaration(parameterName, parameterType),
71-
indexSignature.questionToken,
72-
indexSignature.type)
73-
];
74+
const heritageClauses = getInterfaceHeritageClauses(declaration);
75+
const mappedTypeParameter = createTypeParameterDeclaration(parameterName, parameterType);
76+
const mappedIntersectionType = createMappedTypeNode(
77+
hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
78+
mappedTypeParameter,
79+
indexSignature.questionToken,
80+
indexSignature.type);
7481

7582
return createTypeAliasDeclaration(
7683
declaration.decorators,
7784
declaration.modifiers,
7885
declaration.name,
7986
declaration.typeParameters,
80-
createIntersectionTypeNode(append(mappedIntersectionType, otherMembers.length ? createTypeLiteralNode(otherMembers) : undefined))
87+
createIntersectionTypeNode(
88+
concatenate(
89+
heritageClauses,
90+
append<TypeNode>([mappedIntersectionType], otherMembers.length ? createTypeLiteralNode(otherMembers) : undefined)
91+
)
92+
)
8193
);
8294
}
8395

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar<T> { bar: T; }
6+
//// interface SomeType<T> extends Foo, Bar<T> {
7+
//// a: number;
8+
//// b: T;
9+
//// [prop: K]: any;
10+
//// }
11+
12+
verify.codeFix({
13+
description: `Convert 'SomeType' to mapped object type`,
14+
newFileContent: `type K = "foo" | "bar";
15+
interface Foo { }
16+
interface Bar<T> { bar: T; }
17+
type SomeType<T> = Foo & Bar<T> & {
18+
[prop in K]: any;
19+
} & {
20+
a: number;
21+
b: T;
22+
};`
23+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar<T> { bar: T; }
6+
//// interface SomeType<T> extends Foo, Bar<T> {
7+
//// a: number;
8+
//// b: T;
9+
//// readonly [prop: K]: any;
10+
//// }
11+
12+
verify.codeFix({
13+
description: `Convert 'SomeType' to mapped object type`,
14+
newFileContent: `type K = "foo" | "bar";
15+
interface Foo { }
16+
interface Bar<T> { bar: T; }
17+
type SomeType<T> = Foo & Bar<T> & {
18+
readonly [prop in K]: any;
19+
} & {
20+
a: number;
21+
b: T;
22+
};`
23+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar<T> { bar: T; }
6+
//// interface SomeType<T> extends Foo, Bar<T> {
7+
//// a: number;
8+
//// b: T;
9+
//// readonly [prop: K]?: any;
10+
//// }
11+
12+
verify.not.codeFixAvailable()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface SomeType extends Foo {
6+
//// [prop: K]: any;
7+
//// }
8+
9+
verify.codeFix({
10+
description: `Convert 'SomeType' to mapped object type`,
11+
newFileContent: `type K = "foo" | "bar";
12+
interface Foo { }
13+
type SomeType = Foo & {
14+
[prop in K]: any;
15+
};`
16+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar { }
6+
//// interface SomeType extends Foo, Bar {
7+
//// [prop: K]: any;
8+
//// }
9+
10+
verify.codeFix({
11+
description: `Convert 'SomeType' to mapped object type`,
12+
newFileContent: `type K = "foo" | "bar";
13+
interface Foo { }
14+
interface Bar { }
15+
type SomeType = Foo & Bar & {
16+
[prop in K]: any;
17+
};`
18+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar { }
6+
//// interface SomeType extends Foo, Bar {
7+
//// a: number;
8+
//// [prop: K]: any;
9+
//// }
10+
11+
verify.codeFix({
12+
description: `Convert 'SomeType' to mapped object type`,
13+
newFileContent: `type K = "foo" | "bar";
14+
interface Foo { }
15+
interface Bar { }
16+
type SomeType = Foo & Bar & {
17+
[prop in K]: any;
18+
} & {
19+
a: number;
20+
};`
21+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// type K = "foo" | "bar";
4+
//// interface Foo { }
5+
//// interface Bar<T> { bar: T; }
6+
//// interface SomeType extends Foo, Bar<number> {
7+
//// a: number;
8+
//// [prop: K]: any;
9+
//// }
10+
11+
verify.codeFix({
12+
description: `Convert 'SomeType' to mapped object type`,
13+
newFileContent: `type K = "foo" | "bar";
14+
interface Foo { }
15+
interface Bar<T> { bar: T; }
16+
type SomeType = Foo & Bar<number> & {
17+
[prop in K]: any;
18+
} & {
19+
a: number;
20+
};`
21+
})

0 commit comments

Comments
 (0)