Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12789,7 +12789,7 @@ namespace ts {

function isValidIndexKeyType(type: Type): boolean {
return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) ||
!!(type.flags & TypeFlags.Intersection) && !isGenericIndexType(type) && !isGenericObjectType(type) && some((type as IntersectionType).types, isValidIndexKeyType);
!!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType);
}

function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined {
Expand Down Expand Up @@ -14545,10 +14545,14 @@ namespace ts {
return neverType;
}

function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean {
return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include)));
}

function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) {
const origin = includeOrigin && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) ? createOriginIndexType(type) : undefined;
const propertyTypes = map(getPropertiesOfType(type), prop => getLiteralTypeFromProperty(prop, include));
const indexKeyTypes = map(getIndexInfosOfType(type), info => info !== enumNumberIndexInfo && info.keyType.flags & include ?
const indexKeyTypes = map(getIndexInfosOfType(type), info => info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) ?
info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType : neverType);
return getUnionType(concatenate(propertyTypes, indexKeyTypes), UnionReduction.Literal,
/*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin);
Expand Down
9 changes: 9 additions & 0 deletions tests/baselines/reference/indexSignatures1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,13 @@ tests/cases/conformance/types/members/indexSignatures1.ts(312,43): error TS2322:
~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ [sym]: string; }' is not assignable to type '{ [key: number]: string; }'.
!!! error TS2322: Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'.

// Repro from #45772

type Id = string & { __tag: 'id '};
type Rec1 = { [key: Id]: number };
type Rec2 = Record<Id, number>;

type K1 = keyof Rec1; // Id
type K2 = keyof Rec2; // Id

18 changes: 18 additions & 0 deletions tests/baselines/reference/indexSignatures1.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,15 @@ const aa: AA = { [sym]: '123' };
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error

// Repro from #45772

type Id = string & { __tag: 'id '};
type Rec1 = { [key: Id]: number };
type Rec2 = Record<Id, number>;

type K1 = keyof Rec1; // Id
type K2 = keyof Rec2; // Id


//// [indexSignatures1.js]
Expand Down Expand Up @@ -660,3 +669,12 @@ declare const obj2: {
declare const obj3: {
[key: number]: string;
};
declare type Id = string & {
__tag: 'id ';
};
declare type Rec1 = {
[key: Id]: number;
};
declare type Rec2 = Record<Id, number>;
declare type K1 = keyof Rec1;
declare type K2 = keyof Rec2;
24 changes: 24 additions & 0 deletions tests/baselines/reference/indexSignatures1.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -899,3 +899,27 @@ const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 311, 41))
>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5))

// Repro from #45772

type Id = string & { __tag: 'id '};
>Id : Symbol(Id, Decl(indexSignatures1.ts, 311, 59))
>__tag : Symbol(__tag, Decl(indexSignatures1.ts, 315, 20))

type Rec1 = { [key: Id]: number };
>Rec1 : Symbol(Rec1, Decl(indexSignatures1.ts, 315, 35))
>key : Symbol(key, Decl(indexSignatures1.ts, 316, 15))
>Id : Symbol(Id, Decl(indexSignatures1.ts, 311, 59))

type Rec2 = Record<Id, number>;
>Rec2 : Symbol(Rec2, Decl(indexSignatures1.ts, 316, 34))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>Id : Symbol(Id, Decl(indexSignatures1.ts, 311, 59))

type K1 = keyof Rec1; // Id
>K1 : Symbol(K1, Decl(indexSignatures1.ts, 317, 31))
>Rec1 : Symbol(Rec1, Decl(indexSignatures1.ts, 315, 35))

type K2 = keyof Rec2; // Id
>K2 : Symbol(K2, Decl(indexSignatures1.ts, 319, 21))
>Rec2 : Symbol(Rec2, Decl(indexSignatures1.ts, 316, 34))

19 changes: 19 additions & 0 deletions tests/baselines/reference/indexSignatures1.types
Original file line number Diff line number Diff line change
Expand Up @@ -1051,3 +1051,22 @@ const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
>sym : unique symbol
>'hello ' : "hello "

// Repro from #45772

type Id = string & { __tag: 'id '};
>Id : Id
>__tag : "id "

type Rec1 = { [key: Id]: number };
>Rec1 : Rec1
>key : Id

type Rec2 = Record<Id, number>;
>Rec2 : Rec2

type K1 = keyof Rec1; // Id
>K1 : Id

type K2 = keyof Rec2; // Id
>K2 : Id

9 changes: 9 additions & 0 deletions tests/cases/conformance/types/members/indexSignatures1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,12 @@ const aa: AA = { [sym]: '123' };
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error

// Repro from #45772

type Id = string & { __tag: 'id '};
type Rec1 = { [key: Id]: number };
type Rec2 = Record<Id, number>;

type K1 = keyof Rec1; // Id
type K2 = keyof Rec2; // Id