Skip to content

Commit 32e75f7

Browse files
committed
Separate specfication of type and contextual type
This is basically a bad idea, but it kind of works and might provide ideas for future work.
1 parent f3a12d1 commit 32e75f7

File tree

3 files changed

+30
-13
lines changed

3 files changed

+30
-13
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,15 +3504,19 @@ namespace ts {
35043504
return isPrivateWithinAmbient(memberDeclaration);
35053505
}
35063506

3507-
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
3507+
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol, crazy?: boolean): Type {
3508+
const declaration = symbol.valueDeclaration;
3509+
if (crazy && declaration.kind === SyntaxKind.Parameter && (declaration as ParameterDeclaration).contextualType) {
3510+
// TODO: Doesn't widen of course
3511+
return getTypeFromTypeNode((declaration as ParameterDeclaration).contextualType);
3512+
}
35083513
const links = getSymbolLinks(symbol);
35093514
if (!links.type) {
35103515
// Handle prototype property
35113516
if (symbol.flags & SymbolFlags.Prototype) {
35123517
return links.type = getTypeOfPrototypeProperty(symbol);
35133518
}
35143519
// Handle catch clause variables
3515-
const declaration = symbol.valueDeclaration;
35163520
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
35173521
return links.type = anyType;
35183522
}
@@ -3695,13 +3699,16 @@ namespace ts {
36953699
return links.type;
36963700
}
36973701

3698-
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
3702+
function getTypeOfInstantiatedSymbol(symbol: Symbol, crazy?: boolean): Type {
36993703
const links = getSymbolLinks(symbol);
3704+
if (crazy) {
3705+
return instantiateType(getTypeOfSymbol(links.target, crazy), links.mapper);
3706+
}
37003707
if (!links.type) {
37013708
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
37023709
return unknownType;
37033710
}
3704-
let type = instantiateType(getTypeOfSymbol(links.target), links.mapper);
3711+
let type = instantiateType(getTypeOfSymbol(links.target, crazy), links.mapper);
37053712
if (!popTypeResolution()) {
37063713
type = reportCircularityError(symbol);
37073714
}
@@ -3725,12 +3732,12 @@ namespace ts {
37253732
return anyType;
37263733
}
37273734

3728-
function getTypeOfSymbol(symbol: Symbol): Type {
3735+
function getTypeOfSymbol(symbol: Symbol, crazy?: boolean): Type {
37293736
if (symbol.flags & SymbolFlags.Instantiated) {
3730-
return getTypeOfInstantiatedSymbol(symbol);
3737+
return getTypeOfInstantiatedSymbol(symbol, crazy);
37313738
}
37323739
if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
3733-
return getTypeOfVariableOrParameterOrProperty(symbol);
3740+
return getTypeOfVariableOrParameterOrProperty(symbol, crazy);
37343741
}
37353742
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
37363743
return getTypeOfFuncClassEnumModule(symbol);
@@ -9073,7 +9080,7 @@ namespace ts {
90739080
// We're inferring from some source type S to a mapped type { [P in T]: X }, where T is a type
90749081
// parameter. Infer from 'keyof S' to T and infer from a union of each property type in S to X.
90759082
inferFromTypes(getIndexType(source), constraintType);
9076-
inferFromTypes(getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)), getTemplateTypeFromMappedType(<MappedType>target));
9083+
inferFromTypes(getUnionType(map(getPropertiesOfType(source), p => getTypeOfSymbol(p))), getTemplateTypeFromMappedType(<MappedType>target));
90779084
return;
90789085
}
90799086
}
@@ -11262,7 +11269,7 @@ namespace ts {
1126211269
const argIndex = indexOf(args, arg);
1126311270
if (argIndex >= 0) {
1126411271
const signature = getResolvedOrAnySignature(callTarget);
11265-
return getTypeAtPosition(signature, argIndex);
11272+
return getSpecialContextualTypeAtPosition(signature, argIndex);
1126611273
}
1126711274
return undefined;
1126811275
}
@@ -13097,7 +13104,7 @@ namespace ts {
1309713104
// If the effective argument is 'undefined', then it is an argument that is present but is synthetic.
1309813105
if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) {
1309913106
// Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
13100-
const paramType = getTypeAtPosition(signature, i);
13107+
const paramType = getSpecialContextualTypeAtPosition(signature, i);
1310113108
let argType = getEffectiveArgumentType(node, i);
1310213109

1310313110
// If the effective argument type is 'undefined', there is no synthetic type
@@ -14121,8 +14128,8 @@ namespace ts {
1412114128
}
1412214129
}
1412314130

14124-
function getTypeOfParameter(symbol: Symbol) {
14125-
const type = getTypeOfSymbol(symbol);
14131+
function getTypeOfParameter(symbol: Symbol, crazy?: boolean) {
14132+
const type = getTypeOfSymbol(symbol, crazy);
1412614133
if (strictNullChecks) {
1412714134
const declaration = symbol.valueDeclaration;
1412814135
if (declaration && (<VariableLikeDeclaration>declaration).initializer) {
@@ -14132,6 +14139,12 @@ namespace ts {
1413214139
return type;
1413314140
}
1413414141

14142+
function getSpecialContextualTypeAtPosition(signature: Signature, pos: number): Type {
14143+
return signature.hasRestParameter ?
14144+
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos], /*crazy*/ true) : getRestTypeOfSignature(signature) :
14145+
pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos], /*crazy*/ true) : anyType;
14146+
}
14147+
1413514148
function getTypeAtPosition(signature: Signature, pos: number): Type {
1413614149
return signature.hasRestParameter ?
1413714150
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos]) : getRestTypeOfSignature(signature) :

src/compiler/parser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ namespace ts {
8989
visitNode(cbNode, (<VariableLikeDeclaration>node).name) ||
9090
visitNode(cbNode, (<VariableLikeDeclaration>node).questionToken) ||
9191
visitNode(cbNode, (<VariableLikeDeclaration>node).type) ||
92+
visitNode(cbNode, (<ParameterDeclaration>node).contextualType) ||
9293
visitNode(cbNode, (<VariableLikeDeclaration>node).initializer);
9394
case SyntaxKind.FunctionType:
9495
case SyntaxKind.ConstructorType:
@@ -2117,7 +2118,6 @@ namespace ts {
21172118
if (parseOptional(SyntaxKind.ColonToken)) {
21182119
return parseType();
21192120
}
2120-
21212121
return undefined;
21222122
}
21232123

@@ -2154,6 +2154,9 @@ namespace ts {
21542154

21552155
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
21562156
node.type = parseParameterType();
2157+
if (parseOptional(SyntaxKind.AsKeyword)) {
2158+
node.contextualType = parseType();
2159+
}
21572160
node.initializer = parseBindingElementInitializer(/*inParameter*/ true);
21582161

21592162
// Do not check for initializers in an ambient context for parameters. This is not

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@
666666
name: BindingName; // Declared parameter name
667667
questionToken?: QuestionToken; // Present on optional parameter
668668
type?: TypeNode; // Optional type annotation
669+
contextualType?: TypeNode; // Super-optional contextual type annotation
669670
initializer?: Expression; // Optional initializer
670671
}
671672

0 commit comments

Comments
 (0)