Skip to content

Commit 6b1a425

Browse files
committed
Add functionality to capture type aliases with type parameters
1 parent 309e066 commit 6b1a425

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

debug/debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { transformNode } from '../src/transform-inline/transform-node';
88
import { PartialVisitorContext } from '../src/transform-inline/visitor-context';
99

1010
const configFilename = path.resolve('tsconfig.json');
11-
const inFile = path.resolve('test-fixtures', 'issue-52.ts');
11+
const inFile = path.resolve('test', 'issue-59.ts');
1212
const content = ts.sys.readFile(configFilename);
1313
if (content === undefined) {
1414
throw new Error('Could not read config file.');

src/transform-inline/visitor-type-check.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,17 @@ function visitRegularObjectType(type: ts.ObjectType, visitorContext: VisitorCont
428428
});
429429
}
430430

431+
function visitTypeAliasReference(type: ts.TypeReference, visitorContext: VisitorContext) {
432+
const mapping: Map<ts.Type, ts.Type> = VisitorUtils.getTypeAliasMapping(type);
433+
const previousTypeReference = visitorContext.previousTypeReference;
434+
visitorContext.typeMapperStack.push(mapping);
435+
visitorContext.previousTypeReference = type;
436+
const result = visitType(type, visitorContext);
437+
visitorContext.previousTypeReference = previousTypeReference;
438+
visitorContext.typeMapperStack.pop();
439+
return result;
440+
}
441+
431442
function visitTypeReference(type: ts.TypeReference, visitorContext: VisitorContext) {
432443
const mapping: Map<ts.Type, ts.Type> = VisitorUtils.getTypeReferenceMapping(type, visitorContext);
433444
const previousTypeReference = visitorContext.previousTypeReference;
@@ -683,7 +694,9 @@ function visitIndexedAccessType(type: ts.IndexedAccessType, visitorContext: Visi
683694
}
684695

685696
export function visitType(type: ts.Type, visitorContext: VisitorContext): string {
686-
if ((ts.TypeFlags.Any & type.flags) !== 0) {
697+
if (type.aliasTypeArguments && visitorContext.previousTypeReference !== type && (type as ts.TypeReference).target) {
698+
return visitTypeAliasReference(type as ts.TypeReference, visitorContext);
699+
} else if ((ts.TypeFlags.Any & type.flags) !== 0) {
687700
// Any
688701
return visitAny(visitorContext);
689702
} else if ((ts.TypeFlags.Unknown & type.flags) !== 0) {

src/transform-inline/visitor-utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ export function getPropertyInfo(parentType: ts.Type, symbol: ts.Symbol, visitorC
118118
throw new Error('Expected a valueDeclaration or a property type.');
119119
}
120120

121+
export function getTypeAliasMapping(type: ts.TypeReference) {
122+
const mapping: Map<ts.Type, ts.Type> = new Map();
123+
if (type.aliasTypeArguments !== undefined && type.target.aliasTypeArguments !== undefined) {
124+
const typeParameters = type.target.aliasTypeArguments;
125+
const typeArguments = type.aliasTypeArguments;
126+
for (let i = 0; i < typeParameters.length; i++) {
127+
if (typeParameters[i] !== typeArguments[i]) {
128+
mapping.set(typeParameters[i], typeArguments[i]);
129+
}
130+
}
131+
}
132+
return mapping;
133+
}
134+
121135
export function getTypeReferenceMapping(type: ts.TypeReference, visitorContext: VisitorContext) {
122136
const mapping: Map<ts.Type, ts.Type> = new Map();
123137
(function checkBaseTypes(type: ts.TypeReference) {

test/issue-59.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as assert from 'assert';
2+
import { is } from '../index';
3+
4+
/* https://github.com/woutervh-/typescript-is/issues/59 */
5+
6+
describe('is', () => {
7+
type Row<T> = {
8+
value: T;
9+
};
10+
11+
describe('is<Row<number>>', () => {
12+
it('should return true for Row objects with value a number', () => {
13+
assert.deepStrictEqual(is<Row<number>>({ value: 0 }), true);
14+
assert.deepStrictEqual(is<Row<number>>({ value: 1 }), true);
15+
assert.deepStrictEqual(is<Row<number>>({ value: Number.NaN }), true);
16+
});
17+
18+
it('should return false for Row objects with value not a number', () => {
19+
assert.deepStrictEqual(is<Row<number>>({ value: '0' }), false);
20+
assert.deepStrictEqual(is<Row<number>>({ value: '1' }), false);
21+
assert.deepStrictEqual(is<Row<number>>({ value: true }), false);
22+
assert.deepStrictEqual(is<Row<number>>({ value: false }), false);
23+
assert.deepStrictEqual(is<Row<number>>({ value: {} }), false);
24+
assert.deepStrictEqual(is<Row<number>>({ value: [] }), false);
25+
assert.deepStrictEqual(is<Row<number>>({ value: null }), false);
26+
assert.deepStrictEqual(is<Row<number>>({ value: undefined }), false);
27+
});
28+
});
29+
});

0 commit comments

Comments
 (0)