mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
When relating a deferred index type over a mapped type on the source side ... (#56742)
This commit is contained in:
parent
3b1db10290
commit
bc74ec41a3
@ -22228,6 +22228,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getApparentMappedTypeKeys(nameType: Type, targetType: MappedType) {
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType));
|
||||
const mappedKeys: Type[] = [];
|
||||
forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(
|
||||
modifiersType,
|
||||
TypeFlags.StringOrNumberLiteralOrUnique,
|
||||
/*stringsOnly*/ false,
|
||||
t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))),
|
||||
);
|
||||
return getUnionType(mappedKeys);
|
||||
}
|
||||
|
||||
function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType<typeof captureErrorCalculationState>): Ternary {
|
||||
let result: Ternary;
|
||||
let originalErrorInfo: DiagnosticMessageChain | undefined;
|
||||
@ -22391,16 +22403,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (nameType && isMappedTypeWithKeyofConstraintDeclaration(targetType)) {
|
||||
// we need to get the apparent mappings and union them with the generic mappings, since some properties may be
|
||||
// missing from the `constraintType` which will otherwise be mapped in the object
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(targetType));
|
||||
const mappedKeys: Type[] = [];
|
||||
forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(
|
||||
modifiersType,
|
||||
TypeFlags.StringOrNumberLiteralOrUnique,
|
||||
/*stringsOnly*/ false,
|
||||
t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))),
|
||||
);
|
||||
const mappedKeys = getApparentMappedTypeKeys(nameType, targetType);
|
||||
// We still need to include the non-apparent (and thus still generic) keys in the target side of the comparison (in case they're in the source side)
|
||||
targetKeys = getUnionType([...mappedKeys, nameType]);
|
||||
targetKeys = getUnionType([mappedKeys, nameType]);
|
||||
}
|
||||
else {
|
||||
targetKeys = nameType || constraintType;
|
||||
@ -22593,9 +22598,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
else if (sourceFlags & TypeFlags.Index) {
|
||||
if (result = isRelatedTo(keyofConstraintType, target, RecursionFlags.Source, reportErrors)) {
|
||||
const isDeferredMappedIndex = shouldDeferIndexType((source as IndexType).type, (source as IndexType).indexFlags) && getObjectFlags((source as IndexType).type) & ObjectFlags.Mapped;
|
||||
if (result = isRelatedTo(keyofConstraintType, target, RecursionFlags.Source, reportErrors && !isDeferredMappedIndex)) {
|
||||
return result;
|
||||
}
|
||||
if (isDeferredMappedIndex) {
|
||||
const mappedType = (source as IndexType).type as MappedType;
|
||||
const nameType = getNameTypeFromMappedType(mappedType);
|
||||
// Unlike on the target side, on the source side we do *not* include the generic part of the `nameType`, since that comes from a
|
||||
// (potentially anonymous) mapped type local type parameter, so that'd never assign outside the mapped type body, but we still want to
|
||||
// allow assignments of index types of identical (or similar enough) mapped types.
|
||||
// eg, `keyof {[X in keyof A]: Obj[X]}` should be assignable to `keyof {[Y in keyof A]: Tup[Y]}` because both map over the same set of keys (`keyof A`).
|
||||
// Without this source-side breakdown, a `keyof {[X in keyof A]: Obj[X]}` style type won't be assignable to anything except itself, which is much too strict.
|
||||
const sourceMappedKeys = nameType && isMappedTypeWithKeyofConstraintDeclaration(mappedType) ? getApparentMappedTypeKeys(nameType, mappedType) : (nameType || getConstraintTypeFromMappedType(mappedType));
|
||||
if (result = isRelatedTo(sourceMappedKeys, target, RecursionFlags.Source, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sourceFlags & TypeFlags.TemplateLiteral && !(targetFlags & TypeFlags.Object)) {
|
||||
if (!(targetFlags & TypeFlags.TemplateLiteral)) {
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
//// [tests/cases/compiler/declarationEmitNestedAnonymousMappedType.ts] ////
|
||||
|
||||
//// [declarationEmitNestedAnonymousMappedType.ts]
|
||||
export function enumFromStrings<const Members extends readonly string[]>() {
|
||||
type Part1 = {
|
||||
[key in keyof Members as Members[key] extends string
|
||||
? Members[key]
|
||||
: never]: Members[key];
|
||||
};
|
||||
type Part2 = { [Property in keyof Part1]: Part1[Property] };
|
||||
return Object.create(null) as Part2;
|
||||
}
|
||||
|
||||
|
||||
//// [declarationEmitNestedAnonymousMappedType.js]
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.enumFromStrings = void 0;
|
||||
function enumFromStrings() {
|
||||
return Object.create(null);
|
||||
}
|
||||
exports.enumFromStrings = enumFromStrings;
|
||||
|
||||
|
||||
//// [declarationEmitNestedAnonymousMappedType.d.ts]
|
||||
export declare function enumFromStrings<const Members extends readonly string[]>(): { [Property in keyof { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }]: { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }[Property]; };
|
||||
@ -0,0 +1,39 @@
|
||||
//// [tests/cases/compiler/declarationEmitNestedAnonymousMappedType.ts] ////
|
||||
|
||||
=== declarationEmitNestedAnonymousMappedType.ts ===
|
||||
export function enumFromStrings<const Members extends readonly string[]>() {
|
||||
>enumFromStrings : Symbol(enumFromStrings, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 0))
|
||||
>Members : Symbol(Members, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 32))
|
||||
|
||||
type Part1 = {
|
||||
>Part1 : Symbol(Part1, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 76))
|
||||
|
||||
[key in keyof Members as Members[key] extends string
|
||||
>key : Symbol(key, Decl(declarationEmitNestedAnonymousMappedType.ts, 2, 9))
|
||||
>Members : Symbol(Members, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 32))
|
||||
>Members : Symbol(Members, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 32))
|
||||
>key : Symbol(key, Decl(declarationEmitNestedAnonymousMappedType.ts, 2, 9))
|
||||
|
||||
? Members[key]
|
||||
>Members : Symbol(Members, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 32))
|
||||
>key : Symbol(key, Decl(declarationEmitNestedAnonymousMappedType.ts, 2, 9))
|
||||
|
||||
: never]: Members[key];
|
||||
>Members : Symbol(Members, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 32))
|
||||
>key : Symbol(key, Decl(declarationEmitNestedAnonymousMappedType.ts, 2, 9))
|
||||
|
||||
};
|
||||
type Part2 = { [Property in keyof Part1]: Part1[Property] };
|
||||
>Part2 : Symbol(Part2, Decl(declarationEmitNestedAnonymousMappedType.ts, 5, 6))
|
||||
>Property : Symbol(Property, Decl(declarationEmitNestedAnonymousMappedType.ts, 6, 20))
|
||||
>Part1 : Symbol(Part1, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 76))
|
||||
>Part1 : Symbol(Part1, Decl(declarationEmitNestedAnonymousMappedType.ts, 0, 76))
|
||||
>Property : Symbol(Property, Decl(declarationEmitNestedAnonymousMappedType.ts, 6, 20))
|
||||
|
||||
return Object.create(null) as Part2;
|
||||
>Object.create : Symbol(ObjectConstructor.create, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>create : Symbol(ObjectConstructor.create, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>Part2 : Symbol(Part2, Decl(declarationEmitNestedAnonymousMappedType.ts, 5, 6))
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
//// [tests/cases/compiler/declarationEmitNestedAnonymousMappedType.ts] ////
|
||||
|
||||
=== declarationEmitNestedAnonymousMappedType.ts ===
|
||||
export function enumFromStrings<const Members extends readonly string[]>() {
|
||||
>enumFromStrings : <const Members extends readonly string[]>() => { [Property in keyof { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }]: { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }[Property]; }
|
||||
|
||||
type Part1 = {
|
||||
>Part1 : { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }
|
||||
|
||||
[key in keyof Members as Members[key] extends string
|
||||
? Members[key]
|
||||
: never]: Members[key];
|
||||
};
|
||||
type Part2 = { [Property in keyof Part1]: Part1[Property] };
|
||||
>Part2 : { [Property in keyof { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }]: { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }[Property]; }
|
||||
|
||||
return Object.create(null) as Part2;
|
||||
>Object.create(null) as Part2 : { [Property in keyof { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }]: { [key in keyof Members as Members[key] extends string ? Members[key] : never]: Members[key]; }[Property]; }
|
||||
>Object.create(null) : any
|
||||
>Object.create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
|
||||
>Object : ObjectConstructor
|
||||
>create : { (o: object): any; (o: object, properties: PropertyDescriptorMap & ThisType<any>): any; }
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
// @declaration: true
|
||||
export function enumFromStrings<const Members extends readonly string[]>() {
|
||||
type Part1 = {
|
||||
[key in keyof Members as Members[key] extends string
|
||||
? Members[key]
|
||||
: never]: Members[key];
|
||||
};
|
||||
type Part2 = { [Property in keyof Part1]: Part1[Property] };
|
||||
return Object.create(null) as Part2;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user