@@ -572,8 +572,10 @@ namespace ts {
572
572
}
573
573
574
574
const enum MappedTypeModifiers {
575
- Readonly = 1 << 0,
576
- Optional = 1 << 1,
575
+ IncludeReadonly = 1 << 0,
576
+ ExcludeReadonly = 1 << 1,
577
+ IncludeOptional = 1 << 2,
578
+ ExcludeOptional = 1 << 3,
577
579
}
578
580
579
581
const enum ExpandingFlags {
@@ -2967,11 +2969,10 @@ namespace ts {
2967
2969
2968
2970
function createMappedTypeNodeFromType(type: MappedType) {
2969
2971
Debug.assert(!!(type.flags & TypeFlags.Object));
2970
- const readonlyToken = type.declaration && type.declaration. readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword ) : undefined;
2971
- const questionToken = type.declaration && type.declaration. questionToken ? createToken(SyntaxKind.QuestionToken ) : undefined;
2972
+ const readonlyToken = type.declaration. readonlyToken ? <ReadonlyToken | PlusToken | MinusToken> createToken(type.declaration.readonlyToken.kind ) : undefined;
2973
+ const questionToken = type.declaration. questionToken ? <QuestionToken | PlusToken | MinusToken> createToken(type.declaration.questionToken.kind ) : undefined;
2972
2974
const typeParameterNode = typeParameterToDeclaration(getTypeParameterFromMappedType(type), context, getConstraintTypeFromMappedType(type));
2973
2975
const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context);
2974
-
2975
2976
const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
2976
2977
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
2977
2978
}
@@ -5819,8 +5820,9 @@ namespace ts {
5819
5820
5820
5821
function resolveReverseMappedTypeMembers(type: ReverseMappedType) {
5821
5822
const indexInfo = getIndexInfoOfType(type.source, IndexKind.String);
5822
- const readonlyMask = type.mappedType.declaration.readonlyToken ? false : true;
5823
- const optionalMask = type.mappedType.declaration.questionToken ? 0 : SymbolFlags.Optional;
5823
+ const modifiers = getMappedTypeModifiers(type.mappedType);
5824
+ const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
5825
+ const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
5824
5826
const stringIndexInfo = indexInfo && createIndexInfo(inferReverseMappedType(indexInfo.type, type.mappedType), readonlyMask && indexInfo.isReadonly);
5825
5827
const members = createSymbolTable();
5826
5828
for (const prop of getPropertiesOfType(type.source)) {
@@ -5846,8 +5848,7 @@ namespace ts {
5846
5848
const constraintType = getConstraintTypeFromMappedType(type);
5847
5849
const templateType = getTemplateTypeFromMappedType(<MappedType>type.target || type);
5848
5850
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
5849
- const templateReadonly = !!type.declaration.readonlyToken;
5850
- const templateOptional = !!type.declaration.questionToken;
5851
+ const templateModifiers = getMappedTypeModifiers(type);
5851
5852
const constraintDeclaration = type.declaration.typeParameter.constraint;
5852
5853
if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
5853
5854
(<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
@@ -5888,10 +5889,17 @@ namespace ts {
5888
5889
if (t.flags & TypeFlags.StringLiteral) {
5889
5890
const propName = escapeLeadingUnderscores((<StringLiteralType>t).value);
5890
5891
const modifiersProp = getPropertyOfType(modifiersType, propName);
5891
- const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
5892
- const checkFlags = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp) ? CheckFlags.Readonly : 0;
5893
- const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, checkFlags);
5894
- prop.type = propType;
5892
+ const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional ||
5893
+ !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
5894
+ const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
5895
+ !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
5896
+ const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, isReadonly ? CheckFlags.Readonly : 0);
5897
+ // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the
5898
+ // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks
5899
+ // mode, if the underlying property is optional we remove 'undefined' from the type.
5900
+ prop.type = strictNullChecks && isOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) :
5901
+ strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
5902
+ propType;
5895
5903
if (propertySymbol) {
5896
5904
prop.syntheticOrigin = propertySymbol;
5897
5905
prop.declarations = propertySymbol.declarations;
@@ -5900,7 +5908,7 @@ namespace ts {
5900
5908
members.set(propName, prop);
5901
5909
}
5902
5910
else if (t.flags & (TypeFlags.Any | TypeFlags.String)) {
5903
- stringIndexInfo = createIndexInfo(propType, templateReadonly );
5911
+ stringIndexInfo = createIndexInfo(propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly) );
5904
5912
}
5905
5913
}
5906
5914
}
@@ -5918,7 +5926,7 @@ namespace ts {
5918
5926
function getTemplateTypeFromMappedType(type: MappedType) {
5919
5927
return type.templateType ||
5920
5928
(type.templateType = type.declaration.type ?
5921
- instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!type.declaration.questionToken ), type.mapper || identityMapper) :
5929
+ instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!(getMappedTypeModifiers( type) & MappedTypeModifiers.IncludeOptional) ), type.mapper || identityMapper) :
5922
5930
unknownType);
5923
5931
}
5924
5932
@@ -5946,18 +5954,24 @@ namespace ts {
5946
5954
}
5947
5955
5948
5956
function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
5949
- return (type.declaration.readonlyToken ? MappedTypeModifiers.Readonly : 0) |
5950
- (type.declaration.questionToken ? MappedTypeModifiers.Optional : 0);
5957
+ const declaration = type.declaration;
5958
+ return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) |
5959
+ (declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0);
5960
+ }
5961
+
5962
+ function getMappedTypeOptionality(type: MappedType): number {
5963
+ const modifiers = getMappedTypeModifiers(type);
5964
+ return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0;
5951
5965
}
5952
5966
5953
- function getCombinedMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
5967
+ function getCombinedMappedTypeOptionality(type: MappedType): number {
5968
+ const optionality = getMappedTypeOptionality(type);
5954
5969
const modifiersType = getModifiersTypeFromMappedType(type);
5955
- return getMappedTypeModifiers(type) |
5956
- (isGenericMappedType(modifiersType) ? getMappedTypeModifiers(<MappedType>modifiersType) : 0);
5970
+ return optionality || (isGenericMappedType(modifiersType) ? getMappedTypeOptionality(<MappedType>modifiersType) : 0);
5957
5971
}
5958
5972
5959
5973
function isPartialMappedType(type: Type) {
5960
- return getObjectFlags(type) & ObjectFlags.Mapped && !! (<MappedType>type).declaration.questionToken ;
5974
+ return !!( getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers (<MappedType>type) & MappedTypeModifiers.IncludeOptional) ;
5961
5975
}
5962
5976
5963
5977
function isGenericMappedType(type: Type): type is MappedType {
@@ -9960,7 +9974,7 @@ namespace ts {
9960
9974
if (target.flags & TypeFlags.TypeParameter) {
9961
9975
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
9962
9976
if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>source) === getIndexType(target)) {
9963
- if (!(<MappedType>source).declaration.questionToken ) {
9977
+ if (!(getMappedTypeModifiers( <MappedType>source) & MappedTypeModifiers.IncludeOptional) ) {
9964
9978
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
9965
9979
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
9966
9980
if (result = isRelatedTo(templateType, indexedAccessType, reportErrors)) {
@@ -9999,6 +10013,8 @@ namespace ts {
9999
10013
else if (isGenericMappedType(target)) {
10000
10014
// A source type T is related to a target type { [P in X]: T[P] }
10001
10015
const template = getTemplateTypeFromMappedType(<MappedType>target);
10016
+ const modifiers = getMappedTypeModifiers(<MappedType>target);
10017
+ if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) {
10002
10018
if (template.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>template).objectType === source &&
10003
10019
(<IndexedAccessType>template).indexType === getTypeParameterFromMappedType(<MappedType>target)) {
10004
10020
return Ternary.True;
@@ -10013,6 +10029,7 @@ namespace ts {
10013
10029
}
10014
10030
}
10015
10031
}
10032
+ }
10016
10033
10017
10034
if (source.flags & TypeFlags.TypeParameter) {
10018
10035
let constraint = getConstraintForRelation(<TypeParameter>source);
@@ -10162,8 +10179,7 @@ namespace ts {
10162
10179
function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary {
10163
10180
const modifiersRelated = relation === comparableRelation || (
10164
10181
relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
10165
- !(getCombinedMappedTypeModifiers(source) & MappedTypeModifiers.Optional) ||
10166
- getCombinedMappedTypeModifiers(target) & MappedTypeModifiers.Optional);
10182
+ getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target));
10167
10183
if (modifiersRelated) {
10168
10184
let result: Ternary;
10169
10185
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
@@ -20345,7 +20361,7 @@ namespace ts {
20345
20361
const indexType = (<IndexedAccessType>type).indexType;
20346
20362
if (isTypeAssignableTo(indexType, getIndexType(objectType))) {
20347
20363
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
20348
- getObjectFlags(objectType) & ObjectFlags.Mapped && (<MappedType>objectType).declaration.readonlyToken ) {
20364
+ getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers (<MappedType>objectType) & MappedTypeModifiers.IncludeReadonly ) {
20349
20365
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
20350
20366
}
20351
20367
return type;
0 commit comments