Allow distinct string enum members with identical property names to form unions in mapped types (#39101)

This commit is contained in:
Andrew Branch
2020-06-29 10:08:17 -07:00
committed by GitHub
parent 3853bf5273
commit 58ed610ef1
5 changed files with 307 additions and 15 deletions

View File

@@ -10253,22 +10253,32 @@ namespace ts {
// Otherwise, for type string create a string index signature.
if (isTypeUsableAsPropertyName(t)) {
const propName = getPropertyNameFromType(t);
const modifiersProp = getPropertyOfType(modifiersType, propName);
const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional ||
!(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional;
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
prop.mappedType = type;
prop.mapper = templateMapper;
if (modifiersProp) {
prop.syntheticOrigin = modifiersProp;
prop.declarations = modifiersProp.declarations;
// String enum members from separate enums with identical values
// are distinct types with the same property name. Make the resulting
// property symbol's name type be the union of those enum member types.
const existingProp = members.get(propName) as MappedSymbol | undefined;
if (existingProp) {
existingProp.nameType = getUnionType([existingProp.nameType!, t]);
existingProp.mapper = appendTypeMapping(type.mapper, typeParameter, existingProp.nameType);
}
else {
const modifiersProp = getPropertyOfType(modifiersType, propName);
const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional ||
!(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional;
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
prop.mappedType = type;
if (modifiersProp) {
prop.syntheticOrigin = modifiersProp;
prop.declarations = modifiersProp.declarations;
}
prop.nameType = t;
prop.mapper = templateMapper;
members.set(propName, prop);
}
prop.nameType = t;
members.set(propName, prop);
}
else if (t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.Enum)) {
const propType = instantiateType(templateType, templateMapper);