@@ -2618,8 +2618,8 @@ namespace ts {
2618
2618
2619
2619
function createMappedTypeNodeFromType(type: MappedType) {
2620
2620
Debug.assert(!!(type.flags & TypeFlags.Object));
2621
- const readonlyToken = isReadonlyMappedType( type) ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
2622
- const questionToken = isOptionalMappedType( type) ? createToken(SyntaxKind.QuestionToken) : undefined;
2621
+ const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
2622
+ const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
2623
2623
const typeParameterNode = typeParameterToDeclaration(getTypeParameterFromMappedType(type), context);
2624
2624
const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context);
2625
2625
@@ -3690,7 +3690,7 @@ namespace ts {
3690
3690
writePunctuation(writer, SyntaxKind.OpenBraceToken);
3691
3691
writer.writeLine();
3692
3692
writer.increaseIndent();
3693
- if (isReadonlyMappedType( type) ) {
3693
+ if (type.declaration.readonlyToken ) {
3694
3694
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
3695
3695
writeSpace(writer);
3696
3696
}
@@ -3701,7 +3701,7 @@ namespace ts {
3701
3701
writeSpace(writer);
3702
3702
writeType(getConstraintTypeFromMappedType(type), TypeFormatFlags.None);
3703
3703
writePunctuation(writer, SyntaxKind.CloseBracketToken);
3704
- if (isOptionalMappedType( type) ) {
3704
+ if (type.declaration.questionToken ) {
3705
3705
writePunctuation(writer, SyntaxKind.QuestionToken);
3706
3706
}
3707
3707
writePunctuation(writer, SyntaxKind.ColonToken);
@@ -6038,9 +6038,11 @@ namespace ts {
6038
6038
const constraintType = getConstraintTypeFromMappedType(type);
6039
6039
const templateType = getTemplateTypeFromMappedType(type);
6040
6040
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
6041
- const templateReadonly = isReadonlyMappedType(type);
6042
- const templateOptional = isOptionalMappedType(type);
6043
- if (isPossiblyHomomorphicMappedType(type)) {
6041
+ const templateReadonly = !!type.declaration.readonlyToken;
6042
+ const templateOptional = !!type.declaration.questionToken;
6043
+ const constraintDeclaration = type.declaration.typeParameter.constraint;
6044
+ if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
6045
+ (<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
6044
6046
// We have a { [P in keyof T]: X }
6045
6047
for (const propertySymbol of getPropertiesOfType(modifiersType)) {
6046
6048
addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
@@ -6108,14 +6110,15 @@ namespace ts {
6108
6110
function getTemplateTypeFromMappedType(type: MappedType) {
6109
6111
return type.templateType ||
6110
6112
(type.templateType = type.declaration.type ?
6111
- instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), isOptionalMappedType( type) ), type.mapper || identityMapper) :
6113
+ instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !! type.declaration.questionToken ), type.mapper || identityMapper) :
6112
6114
unknownType);
6113
6115
}
6114
6116
6115
6117
function getModifiersTypeFromMappedType(type: MappedType) {
6116
6118
if (!type.modifiersType) {
6117
- if (isPossiblyHomomorphicMappedType(type)) {
6118
- const constraintDeclaration = type.declaration.typeParameter.constraint;
6119
+ const constraintDeclaration = type.declaration.typeParameter.constraint;
6120
+ if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
6121
+ (<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
6119
6122
// If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check
6120
6123
// AST nodes here because, when T is a non-generic type, the logic below eagerly resolves
6121
6124
// 'keyof T' to a literal union type and we can't recover T from that type.
@@ -6135,8 +6138,8 @@ namespace ts {
6135
6138
}
6136
6139
6137
6140
function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
6138
- return (isReadonlyMappedType( type) ? MappedTypeModifiers.Readonly : 0) |
6139
- (isOptionalMappedType( type) ? MappedTypeModifiers.Optional : 0);
6141
+ return (type.declaration.readonlyToken ? MappedTypeModifiers.Readonly : 0) |
6142
+ (type.declaration.questionToken ? MappedTypeModifiers.Optional : 0);
6140
6143
}
6141
6144
6142
6145
function getCombinedMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
@@ -6146,7 +6149,7 @@ namespace ts {
6146
6149
}
6147
6150
6148
6151
function isPartialMappedType(type: Type) {
6149
- return getObjectFlags(type) & ObjectFlags.Mapped && isOptionalMappedType(type as MappedType) ;
6152
+ return getObjectFlags(type) & ObjectFlags.Mapped && !!(< MappedType>type).declaration.questionToken ;
6150
6153
}
6151
6154
6152
6155
function isGenericMappedType(type: Type) {
@@ -9743,7 +9746,7 @@ namespace ts {
9743
9746
if (target.flags & TypeFlags.TypeParameter) {
9744
9747
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
9745
9748
if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>source) === getIndexType(target)) {
9746
- if (!isOptionalMappedType (<MappedType>source)) {
9749
+ if (!(<MappedType>source).declaration.questionToken ) {
9747
9750
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
9748
9751
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
9749
9752
if (result = isRelatedTo(templateType, indexedAccessType, reportErrors)) {
@@ -11131,8 +11134,8 @@ namespace ts {
11131
11134
const inference = createInferenceInfo(typeParameter);
11132
11135
const inferences = [inference];
11133
11136
const templateType = getTemplateTypeFromMappedType(target);
11134
- const readonlyMask = isReadonlyMappedType( target) ? false : true;
11135
- const optionalMask = isOptionalMappedType( target) ? 0 : SymbolFlags.Optional;
11137
+ const readonlyMask = target.declaration.readonlyToken ? false : true;
11138
+ const optionalMask = target.declaration.questionToken ? 0 : SymbolFlags.Optional;
11136
11139
const members = createSymbolTable();
11137
11140
for (const prop of properties) {
11138
11141
const propType = getTypeOfSymbol(prop);
@@ -11264,18 +11267,14 @@ namespace ts {
11264
11267
const inference = getInferenceInfoForType(targetConstraint);
11265
11268
if (inference) {
11266
11269
if (!inference.isFixed) {
11267
- const map = <MappedType>createObjectType(ObjectFlags.Mapped);
11268
- map.templateType = source;
11269
- map.constraintType = (<IndexedAccessType>target).indexType;
11270
- map.typeParameter = <TypeParameter>createType(TypeFlags.TypeParameter);
11271
- // TODO (weswigham): Ensure the name chosen for the unused "K" does not shadow any other type variables in the given scope, so as to not have a chance of breaking declaration emit
11272
- map.typeParameter.symbol = createSymbol(SymbolFlags.TypeParameter, "K" as __String);
11273
- map.typeParameter.constraint = map.constraintType;
11274
- map.modifiersType = (<IndexedAccessType>target).indexType;
11275
- map.hasQuestionToken = false;
11276
- map.hasReadonlyToken = false;
11277
- map.hasPossiblyHomomorphicConstraint = false;
11278
- (inference.indexes || (inference.indexes = [])).push(map);
11270
+ // Instantiates instance of `type PartialInference<T, Keys extends string> = ({[K in Keys]: {[K1 in K]: T}})[Keys];`
11271
+ // Where `T` is `source` and `Keys` is `target.indexType`
11272
+ const inferenceTypeSymbol = getGlobalSymbol("PartialInference" as __String, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0);
11273
+ const inferenceType = getDeclaredTypeOfSymbol(inferenceTypeSymbol);
11274
+ if (inferenceType !== unknownType) {
11275
+ const mapper = createTypeMapper(getSymbolLinks(inferenceTypeSymbol).typeParameters, [source, (target as IndexedAccessType).indexType]);
11276
+ (inference.indexes || (inference.indexes = [])).push(instantiateType(inferenceType, mapper));
11277
+ }
11279
11278
}
11280
11279
return;
11281
11280
}
@@ -19857,28 +19856,6 @@ namespace ts {
19857
19856
forEach(node.types, checkSourceElement);
19858
19857
}
19859
19858
19860
- function isReadonlyMappedType(type: MappedType) {
19861
- if (type.hasReadonlyToken === undefined) {
19862
- type.hasReadonlyToken = !!type.declaration.readonlyToken;
19863
- }
19864
- return type.hasReadonlyToken;
19865
- }
19866
-
19867
- function isOptionalMappedType(type: MappedType) {
19868
- if (type.hasQuestionToken === undefined) {
19869
- type.hasQuestionToken = !!type.declaration.questionToken;
19870
- }
19871
- return type.hasQuestionToken;
19872
- }
19873
-
19874
- function isPossiblyHomomorphicMappedType(type: MappedType) {
19875
- if (type.hasPossiblyHomomorphicConstraint === undefined) {
19876
- const constraint = type.declaration.typeParameter.constraint;
19877
- type.hasPossiblyHomomorphicConstraint = isTypeOperatorNode(constraint) && constraint.operator === SyntaxKind.KeyOfKeyword;
19878
- }
19879
- return type.hasPossiblyHomomorphicConstraint;
19880
- }
19881
-
19882
19859
function checkIndexedAccessIndexType(type: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode) {
19883
19860
if (!(type.flags & TypeFlags.IndexedAccess)) {
19884
19861
return type;
@@ -19888,7 +19865,7 @@ namespace ts {
19888
19865
const indexType = (<IndexedAccessType>type).indexType;
19889
19866
if (isTypeAssignableTo(indexType, getIndexType(objectType))) {
19890
19867
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
19891
- getObjectFlags(objectType) & ObjectFlags.Mapped && isReadonlyMappedType (<MappedType>objectType)) {
19868
+ getObjectFlags(objectType) & ObjectFlags.Mapped && (<MappedType>objectType).declaration.readonlyToken ) {
19892
19869
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
19893
19870
}
19894
19871
return type;
0 commit comments