mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Allow distinct string enum members with identical property names to form unions in mapped types (#39101)
This commit is contained in:
parent
3853bf5273
commit
58ed610ef1
@ -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);
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
//// [mappedTypeOverlappingStringEnumKeys.ts]
|
||||
// #37859
|
||||
|
||||
enum TerrestrialAnimalTypes {
|
||||
CAT = "cat",
|
||||
DOG = "dog"
|
||||
};
|
||||
|
||||
enum AlienAnimalTypes {
|
||||
CAT = "cat",
|
||||
};
|
||||
|
||||
type AnimalTypes = TerrestrialAnimalTypes | AlienAnimalTypes;
|
||||
|
||||
interface TerrestrialCat {
|
||||
type: TerrestrialAnimalTypes.CAT;
|
||||
address: string;
|
||||
}
|
||||
|
||||
interface AlienCat {
|
||||
type: AlienAnimalTypes.CAT
|
||||
planet: string;
|
||||
}
|
||||
|
||||
type Cats = TerrestrialCat | AlienCat;
|
||||
|
||||
type CatMap = {
|
||||
[V in AnimalTypes]: Extract<Cats, { type: V }>[]
|
||||
};
|
||||
|
||||
const catMap: CatMap = {
|
||||
cat: [
|
||||
{ type: TerrestrialAnimalTypes.CAT, address: "" },
|
||||
{ type: AlienAnimalTypes.CAT, planet: "" }
|
||||
],
|
||||
dog: [] as never[]
|
||||
};
|
||||
|
||||
|
||||
//// [mappedTypeOverlappingStringEnumKeys.js]
|
||||
// #37859
|
||||
var TerrestrialAnimalTypes;
|
||||
(function (TerrestrialAnimalTypes) {
|
||||
TerrestrialAnimalTypes["CAT"] = "cat";
|
||||
TerrestrialAnimalTypes["DOG"] = "dog";
|
||||
})(TerrestrialAnimalTypes || (TerrestrialAnimalTypes = {}));
|
||||
;
|
||||
var AlienAnimalTypes;
|
||||
(function (AlienAnimalTypes) {
|
||||
AlienAnimalTypes["CAT"] = "cat";
|
||||
})(AlienAnimalTypes || (AlienAnimalTypes = {}));
|
||||
;
|
||||
var catMap = {
|
||||
cat: [
|
||||
{ type: TerrestrialAnimalTypes.CAT, address: "" },
|
||||
{ type: AlienAnimalTypes.CAT, planet: "" }
|
||||
],
|
||||
dog: []
|
||||
};
|
||||
@ -0,0 +1,96 @@
|
||||
=== tests/cases/conformance/types/mapped/mappedTypeOverlappingStringEnumKeys.ts ===
|
||||
// #37859
|
||||
|
||||
enum TerrestrialAnimalTypes {
|
||||
>TerrestrialAnimalTypes : Symbol(TerrestrialAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 0, 0))
|
||||
|
||||
CAT = "cat",
|
||||
>CAT : Symbol(TerrestrialAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 2, 29))
|
||||
|
||||
DOG = "dog"
|
||||
>DOG : Symbol(TerrestrialAnimalTypes.DOG, Decl(mappedTypeOverlappingStringEnumKeys.ts, 3, 14))
|
||||
|
||||
};
|
||||
|
||||
enum AlienAnimalTypes {
|
||||
>AlienAnimalTypes : Symbol(AlienAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 5, 2))
|
||||
|
||||
CAT = "cat",
|
||||
>CAT : Symbol(AlienAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 7, 23))
|
||||
|
||||
};
|
||||
|
||||
type AnimalTypes = TerrestrialAnimalTypes | AlienAnimalTypes;
|
||||
>AnimalTypes : Symbol(AnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 9, 2))
|
||||
>TerrestrialAnimalTypes : Symbol(TerrestrialAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 0, 0))
|
||||
>AlienAnimalTypes : Symbol(AlienAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 5, 2))
|
||||
|
||||
interface TerrestrialCat {
|
||||
>TerrestrialCat : Symbol(TerrestrialCat, Decl(mappedTypeOverlappingStringEnumKeys.ts, 11, 61))
|
||||
|
||||
type: TerrestrialAnimalTypes.CAT;
|
||||
>type : Symbol(TerrestrialCat.type, Decl(mappedTypeOverlappingStringEnumKeys.ts, 13, 26))
|
||||
>TerrestrialAnimalTypes : Symbol(TerrestrialAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 0, 0))
|
||||
>CAT : Symbol(TerrestrialAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 2, 29))
|
||||
|
||||
address: string;
|
||||
>address : Symbol(TerrestrialCat.address, Decl(mappedTypeOverlappingStringEnumKeys.ts, 14, 35))
|
||||
}
|
||||
|
||||
interface AlienCat {
|
||||
>AlienCat : Symbol(AlienCat, Decl(mappedTypeOverlappingStringEnumKeys.ts, 16, 1))
|
||||
|
||||
type: AlienAnimalTypes.CAT
|
||||
>type : Symbol(AlienCat.type, Decl(mappedTypeOverlappingStringEnumKeys.ts, 18, 20))
|
||||
>AlienAnimalTypes : Symbol(AlienAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 5, 2))
|
||||
>CAT : Symbol(AlienAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 7, 23))
|
||||
|
||||
planet: string;
|
||||
>planet : Symbol(AlienCat.planet, Decl(mappedTypeOverlappingStringEnumKeys.ts, 19, 28))
|
||||
}
|
||||
|
||||
type Cats = TerrestrialCat | AlienCat;
|
||||
>Cats : Symbol(Cats, Decl(mappedTypeOverlappingStringEnumKeys.ts, 21, 1))
|
||||
>TerrestrialCat : Symbol(TerrestrialCat, Decl(mappedTypeOverlappingStringEnumKeys.ts, 11, 61))
|
||||
>AlienCat : Symbol(AlienCat, Decl(mappedTypeOverlappingStringEnumKeys.ts, 16, 1))
|
||||
|
||||
type CatMap = {
|
||||
>CatMap : Symbol(CatMap, Decl(mappedTypeOverlappingStringEnumKeys.ts, 23, 38))
|
||||
|
||||
[V in AnimalTypes]: Extract<Cats, { type: V }>[]
|
||||
>V : Symbol(V, Decl(mappedTypeOverlappingStringEnumKeys.ts, 26, 3))
|
||||
>AnimalTypes : Symbol(AnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 9, 2))
|
||||
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
|
||||
>Cats : Symbol(Cats, Decl(mappedTypeOverlappingStringEnumKeys.ts, 21, 1))
|
||||
>type : Symbol(type, Decl(mappedTypeOverlappingStringEnumKeys.ts, 26, 37))
|
||||
>V : Symbol(V, Decl(mappedTypeOverlappingStringEnumKeys.ts, 26, 3))
|
||||
|
||||
};
|
||||
|
||||
const catMap: CatMap = {
|
||||
>catMap : Symbol(catMap, Decl(mappedTypeOverlappingStringEnumKeys.ts, 29, 5))
|
||||
>CatMap : Symbol(CatMap, Decl(mappedTypeOverlappingStringEnumKeys.ts, 23, 38))
|
||||
|
||||
cat: [
|
||||
>cat : Symbol(cat, Decl(mappedTypeOverlappingStringEnumKeys.ts, 29, 24))
|
||||
|
||||
{ type: TerrestrialAnimalTypes.CAT, address: "" },
|
||||
>type : Symbol(type, Decl(mappedTypeOverlappingStringEnumKeys.ts, 31, 5))
|
||||
>TerrestrialAnimalTypes.CAT : Symbol(TerrestrialAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 2, 29))
|
||||
>TerrestrialAnimalTypes : Symbol(TerrestrialAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 0, 0))
|
||||
>CAT : Symbol(TerrestrialAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 2, 29))
|
||||
>address : Symbol(address, Decl(mappedTypeOverlappingStringEnumKeys.ts, 31, 39))
|
||||
|
||||
{ type: AlienAnimalTypes.CAT, planet: "" }
|
||||
>type : Symbol(type, Decl(mappedTypeOverlappingStringEnumKeys.ts, 32, 5))
|
||||
>AlienAnimalTypes.CAT : Symbol(AlienAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 7, 23))
|
||||
>AlienAnimalTypes : Symbol(AlienAnimalTypes, Decl(mappedTypeOverlappingStringEnumKeys.ts, 5, 2))
|
||||
>CAT : Symbol(AlienAnimalTypes.CAT, Decl(mappedTypeOverlappingStringEnumKeys.ts, 7, 23))
|
||||
>planet : Symbol(planet, Decl(mappedTypeOverlappingStringEnumKeys.ts, 32, 33))
|
||||
|
||||
],
|
||||
dog: [] as never[]
|
||||
>dog : Symbol(dog, Decl(mappedTypeOverlappingStringEnumKeys.ts, 33, 4))
|
||||
|
||||
};
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
=== tests/cases/conformance/types/mapped/mappedTypeOverlappingStringEnumKeys.ts ===
|
||||
// #37859
|
||||
|
||||
enum TerrestrialAnimalTypes {
|
||||
>TerrestrialAnimalTypes : TerrestrialAnimalTypes
|
||||
|
||||
CAT = "cat",
|
||||
>CAT : TerrestrialAnimalTypes.CAT
|
||||
>"cat" : "cat"
|
||||
|
||||
DOG = "dog"
|
||||
>DOG : TerrestrialAnimalTypes.DOG
|
||||
>"dog" : "dog"
|
||||
|
||||
};
|
||||
|
||||
enum AlienAnimalTypes {
|
||||
>AlienAnimalTypes : AlienAnimalTypes
|
||||
|
||||
CAT = "cat",
|
||||
>CAT : AlienAnimalTypes.CAT
|
||||
>"cat" : "cat"
|
||||
|
||||
};
|
||||
|
||||
type AnimalTypes = TerrestrialAnimalTypes | AlienAnimalTypes;
|
||||
>AnimalTypes : AnimalTypes
|
||||
|
||||
interface TerrestrialCat {
|
||||
type: TerrestrialAnimalTypes.CAT;
|
||||
>type : TerrestrialAnimalTypes.CAT
|
||||
>TerrestrialAnimalTypes : any
|
||||
|
||||
address: string;
|
||||
>address : string
|
||||
}
|
||||
|
||||
interface AlienCat {
|
||||
type: AlienAnimalTypes.CAT
|
||||
>type : AlienAnimalTypes
|
||||
>AlienAnimalTypes : any
|
||||
|
||||
planet: string;
|
||||
>planet : string
|
||||
}
|
||||
|
||||
type Cats = TerrestrialCat | AlienCat;
|
||||
>Cats : Cats
|
||||
|
||||
type CatMap = {
|
||||
>CatMap : CatMap
|
||||
|
||||
[V in AnimalTypes]: Extract<Cats, { type: V }>[]
|
||||
>type : V
|
||||
|
||||
};
|
||||
|
||||
const catMap: CatMap = {
|
||||
>catMap : CatMap
|
||||
>{ cat: [ { type: TerrestrialAnimalTypes.CAT, address: "" }, { type: AlienAnimalTypes.CAT, planet: "" } ], dog: [] as never[]} : { cat: ({ type: TerrestrialAnimalTypes.CAT; address: string; } | { type: AlienAnimalTypes.CAT; planet: string; })[]; dog: never[]; }
|
||||
|
||||
cat: [
|
||||
>cat : ({ type: TerrestrialAnimalTypes.CAT; address: string; } | { type: AlienAnimalTypes.CAT; planet: string; })[]
|
||||
>[ { type: TerrestrialAnimalTypes.CAT, address: "" }, { type: AlienAnimalTypes.CAT, planet: "" } ] : ({ type: TerrestrialAnimalTypes.CAT; address: string; } | { type: AlienAnimalTypes.CAT; planet: string; })[]
|
||||
|
||||
{ type: TerrestrialAnimalTypes.CAT, address: "" },
|
||||
>{ type: TerrestrialAnimalTypes.CAT, address: "" } : { type: TerrestrialAnimalTypes.CAT; address: string; }
|
||||
>type : TerrestrialAnimalTypes.CAT
|
||||
>TerrestrialAnimalTypes.CAT : TerrestrialAnimalTypes.CAT
|
||||
>TerrestrialAnimalTypes : typeof TerrestrialAnimalTypes
|
||||
>CAT : TerrestrialAnimalTypes.CAT
|
||||
>address : string
|
||||
>"" : ""
|
||||
|
||||
{ type: AlienAnimalTypes.CAT, planet: "" }
|
||||
>{ type: AlienAnimalTypes.CAT, planet: "" } : { type: AlienAnimalTypes.CAT; planet: string; }
|
||||
>type : AlienAnimalTypes.CAT
|
||||
>AlienAnimalTypes.CAT : AlienAnimalTypes
|
||||
>AlienAnimalTypes : typeof AlienAnimalTypes
|
||||
>CAT : AlienAnimalTypes
|
||||
>planet : string
|
||||
>"" : ""
|
||||
|
||||
],
|
||||
dog: [] as never[]
|
||||
>dog : never[]
|
||||
>[] as never[] : never[]
|
||||
>[] : undefined[]
|
||||
|
||||
};
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
// #37859
|
||||
|
||||
enum TerrestrialAnimalTypes {
|
||||
CAT = "cat",
|
||||
DOG = "dog"
|
||||
};
|
||||
|
||||
enum AlienAnimalTypes {
|
||||
CAT = "cat",
|
||||
};
|
||||
|
||||
type AnimalTypes = TerrestrialAnimalTypes | AlienAnimalTypes;
|
||||
|
||||
interface TerrestrialCat {
|
||||
type: TerrestrialAnimalTypes.CAT;
|
||||
address: string;
|
||||
}
|
||||
|
||||
interface AlienCat {
|
||||
type: AlienAnimalTypes.CAT
|
||||
planet: string;
|
||||
}
|
||||
|
||||
type Cats = TerrestrialCat | AlienCat;
|
||||
|
||||
type CatMap = {
|
||||
[V in AnimalTypes]: Extract<Cats, { type: V }>[]
|
||||
};
|
||||
|
||||
const catMap: CatMap = {
|
||||
cat: [
|
||||
{ type: TerrestrialAnimalTypes.CAT, address: "" },
|
||||
{ type: AlienAnimalTypes.CAT, planet: "" }
|
||||
],
|
||||
dog: [] as never[]
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user