Skip to content

Commit 9ac7667

Browse files
committed
Address CR feedback
1 parent 5028a44 commit 9ac7667

File tree

2 files changed

+19
-13
lines changed

2 files changed

+19
-13
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4484,33 +4484,33 @@ namespace ts {
44844484
}
44854485
}
44864486

4487-
function forEachType<T>(type: Type, f: (t: Type) => T): T {
4488-
return type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, f) : f(type);
4489-
}
4490-
4491-
// { [P in K]: T }
4492-
// Get apparent type of K
4493-
// If apparent type is a 'keyof T', get apparent type of T
4494-
// For each constituent literal type U
4495-
// create mapper from P to U
4496-
// instantiate T using mapper
4497-
// if U is string or number, create index signature with instantiated type
4498-
// otherwise create property with name from U and instantiated type
4487+
/** Resolve the members of a mapped type { [P in K]: T } */
44994488
function resolveMappedTypeMembers(type: MappedType) {
45004489
const members: SymbolTable = createMap<Symbol>();
45014490
let stringIndexInfo: IndexInfo;
45024491
let numberIndexInfo: IndexInfo;
4492+
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
4493+
// and T as the template type.
45034494
const typeParameter = getTypeParameterFromMappedType(type);
45044495
const constraintType = getConstraintTypeFromMappedType(type);
45054496
const templateType = getTemplateTypeFromMappedType(type);
45064497
const isReadonly = !!type.declaration.readonlyToken;
45074498
const isOptional = !!type.declaration.questionToken;
4499+
// First, if the constraint type is a type parameter, obtain the base constraint. Then,
4500+
// if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
4501+
// Finally, iterate over the constituents of the resulting iteration type.
45084502
const keyType = constraintType.flags & TypeFlags.TypeParameter ? getApparentType(constraintType) : constraintType;
45094503
const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((<IndexType>keyType).type)) : keyType;
45104504
forEachType(iterationType, t => {
4505+
// Create a mapper from T to the current iteration type constituent. Then, if the
4506+
// mapped type is itself an instantiated type, combine the iteration mapper with the
4507+
// instantiation mapper.
45114508
const iterationMapper = createUnaryTypeMapper(typeParameter, t);
45124509
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, iterationMapper) : iterationMapper;
45134510
const propType = instantiateType(templateType, templateMapper);
4511+
// If the current iteration type constituent is a literal type, create a property.
4512+
// Otherwise, for type string create a string index signature and for type number
4513+
// create a numeric index signature.
45144514
if (t.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.EnumLiteral)) {
45154515
const propName = (<LiteralType>t).text;
45164516
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
@@ -4525,6 +4525,8 @@ namespace ts {
45254525
numberIndexInfo = createIndexInfo(propType, isReadonly);
45264526
}
45274527
});
4528+
// If we created both a string and a numeric string index signature, and if the two index
4529+
// signatures have identical types, discard the redundant numeric index signature.
45284530
if (stringIndexInfo && numberIndexInfo && isTypeIdenticalTo(stringIndexInfo.type, numberIndexInfo.type)) {
45294531
numberIndexInfo = undefined;
45304532
}
@@ -9060,6 +9062,10 @@ namespace ts {
90609062
return containsType(target.types, source);
90619063
}
90629064

9065+
function forEachType<T>(type: Type, f: (t: Type) => T): T {
9066+
return type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, f) : f(type);
9067+
}
9068+
90639069
function filterType(type: Type, f: (t: Type) => boolean): Type {
90649070
if (type.flags & TypeFlags.Union) {
90659071
const types = (<UnionType>type).types;

tests/cases/conformance/types/mapped/mappedTypeErrors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type T12 = Pick<Shape, "name" | "foo">; // Error
4343
type T13 = Pick<Shape, keyof Named>;
4444
type T14 = Pick<Shape, keyof Point>; // Error
4545
type T15 = Pick<Shape, never>;
46-
type T16 = Pick<Shape, undefined>;
46+
type T16 = Pick<Shape, undefined>; // Error
4747

4848
function f1<T>(x: T) {
4949
let y: Pick<Shape, T>; // Error

0 commit comments

Comments
 (0)