mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Preserve the homomorphism of inlined mapped types in declaration emit (#48091)
This commit is contained in:
parent
c70be8b501
commit
ea4791d4d7
@ -5079,10 +5079,16 @@ namespace ts {
|
||||
const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) as ReadonlyKeyword | PlusToken | MinusToken : undefined;
|
||||
const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined;
|
||||
let appropriateConstraintTypeNode: TypeNode;
|
||||
let newTypeVariable: TypeReferenceNode | undefined;
|
||||
if (isMappedTypeWithKeyofConstraintDeclaration(type)) {
|
||||
// We have a { [P in keyof T]: X }
|
||||
// We do this to ensure we retain the toplevel keyof-ness of the type which may be lost due to keyof distribution during `getConstraintTypeFromMappedType`
|
||||
appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context));
|
||||
if (!(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
|
||||
const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String));
|
||||
const name = typeParameterToName(newParam, context);
|
||||
newTypeVariable = factory.createTypeReferenceNode(name);
|
||||
}
|
||||
appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context));
|
||||
}
|
||||
else {
|
||||
appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context);
|
||||
@ -5092,7 +5098,19 @@ namespace ts {
|
||||
const templateTypeNode = typeToTypeNodeHelper(removeMissingType(getTemplateTypeFromMappedType(type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context);
|
||||
const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined);
|
||||
context.approximateLength += 10;
|
||||
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
|
||||
const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
|
||||
if (isMappedTypeWithKeyofConstraintDeclaration(type) && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.TypeParameter) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) {
|
||||
// homomorphic mapped type with a non-homomorphic naive inlining
|
||||
// wrap it with a conditional like `SomeModifiersType extends infer U ? {..the mapped type...} : never` to ensure the resulting
|
||||
// type stays homomorphic
|
||||
return factory.createConditionalTypeNode(
|
||||
typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context),
|
||||
factory.createInferTypeNode(factory.createTypeParameterDeclaration(factory.cloneNode(newTypeVariable!.typeName) as Identifier)),
|
||||
result,
|
||||
factory.createKeywordTypeNode(SyntaxKind.NeverKeyword)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createAnonymousTypeNode(type: ObjectType): TypeNode {
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
//// [tests/cases/compiler/mappedTypeGenericInstantiationPreservesHomomorphism.ts] ////
|
||||
|
||||
//// [internal.ts]
|
||||
export declare function usePrivateType<T extends unknown[]>(...args: T): PrivateMapped<T[any]>;
|
||||
|
||||
type PrivateMapped<Obj> = {[K in keyof Obj]: Obj[K]};
|
||||
|
||||
//// [api.ts]
|
||||
import {usePrivateType} from './internal';
|
||||
export const mappedUnionWithPrivateType = <T extends unknown[]>(...args: T) => usePrivateType(...args);
|
||||
|
||||
|
||||
//// [internal.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
//// [api.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.mappedUnionWithPrivateType = void 0;
|
||||
var internal_1 = require("./internal");
|
||||
var mappedUnionWithPrivateType = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return internal_1.usePrivateType.apply(void 0, args);
|
||||
};
|
||||
exports.mappedUnionWithPrivateType = mappedUnionWithPrivateType;
|
||||
|
||||
|
||||
//// [internal.d.ts]
|
||||
export declare function usePrivateType<T extends unknown[]>(...args: T): PrivateMapped<T[any]>;
|
||||
declare type PrivateMapped<Obj> = {
|
||||
[K in keyof Obj]: Obj[K];
|
||||
};
|
||||
export {};
|
||||
//// [api.d.ts]
|
||||
export declare const mappedUnionWithPrivateType: <T extends unknown[]>(...args: T) => T[any] extends infer T_1 ? { [K in keyof T_1]: T[any][K]; } : never;
|
||||
@ -0,0 +1,29 @@
|
||||
=== tests/cases/compiler/internal.ts ===
|
||||
export declare function usePrivateType<T extends unknown[]>(...args: T): PrivateMapped<T[any]>;
|
||||
>usePrivateType : Symbol(usePrivateType, Decl(internal.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(internal.ts, 0, 39))
|
||||
>args : Symbol(args, Decl(internal.ts, 0, 60))
|
||||
>T : Symbol(T, Decl(internal.ts, 0, 39))
|
||||
>PrivateMapped : Symbol(PrivateMapped, Decl(internal.ts, 0, 95))
|
||||
>T : Symbol(T, Decl(internal.ts, 0, 39))
|
||||
|
||||
type PrivateMapped<Obj> = {[K in keyof Obj]: Obj[K]};
|
||||
>PrivateMapped : Symbol(PrivateMapped, Decl(internal.ts, 0, 95))
|
||||
>Obj : Symbol(Obj, Decl(internal.ts, 2, 19))
|
||||
>K : Symbol(K, Decl(internal.ts, 2, 28))
|
||||
>Obj : Symbol(Obj, Decl(internal.ts, 2, 19))
|
||||
>Obj : Symbol(Obj, Decl(internal.ts, 2, 19))
|
||||
>K : Symbol(K, Decl(internal.ts, 2, 28))
|
||||
|
||||
=== tests/cases/compiler/api.ts ===
|
||||
import {usePrivateType} from './internal';
|
||||
>usePrivateType : Symbol(usePrivateType, Decl(api.ts, 0, 8))
|
||||
|
||||
export const mappedUnionWithPrivateType = <T extends unknown[]>(...args: T) => usePrivateType(...args);
|
||||
>mappedUnionWithPrivateType : Symbol(mappedUnionWithPrivateType, Decl(api.ts, 1, 12))
|
||||
>T : Symbol(T, Decl(api.ts, 1, 43))
|
||||
>args : Symbol(args, Decl(api.ts, 1, 64))
|
||||
>T : Symbol(T, Decl(api.ts, 1, 43))
|
||||
>usePrivateType : Symbol(usePrivateType, Decl(api.ts, 0, 8))
|
||||
>args : Symbol(args, Decl(api.ts, 1, 64))
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
=== tests/cases/compiler/internal.ts ===
|
||||
export declare function usePrivateType<T extends unknown[]>(...args: T): PrivateMapped<T[any]>;
|
||||
>usePrivateType : <T extends unknown[]>(...args: T) => PrivateMapped<T[any]>
|
||||
>args : T
|
||||
|
||||
type PrivateMapped<Obj> = {[K in keyof Obj]: Obj[K]};
|
||||
>PrivateMapped : PrivateMapped<Obj>
|
||||
|
||||
=== tests/cases/compiler/api.ts ===
|
||||
import {usePrivateType} from './internal';
|
||||
>usePrivateType : <T extends unknown[]>(...args: T) => { [K in keyof T[any]]: T[any][K]; }
|
||||
|
||||
export const mappedUnionWithPrivateType = <T extends unknown[]>(...args: T) => usePrivateType(...args);
|
||||
>mappedUnionWithPrivateType : <T extends unknown[]>(...args: T) => { [K in keyof T[any]]: T[any][K]; }
|
||||
><T extends unknown[]>(...args: T) => usePrivateType(...args) : <T extends unknown[]>(...args: T) => { [K in keyof T[any]]: T[any][K]; }
|
||||
>args : T
|
||||
>usePrivateType(...args) : { [K in keyof T[any]]: T[any][K]; }
|
||||
>usePrivateType : <T extends unknown[]>(...args: T) => { [K in keyof T[any]]: T[any][K]; }
|
||||
>...args : unknown
|
||||
>args : T
|
||||
|
||||
@ -38,7 +38,7 @@ export declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
export declare type PartialProperties<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
|
||||
export declare function doSomething_Actual<T extends {
|
||||
prop: string;
|
||||
}>(a: T): { [P in keyof PartialProperties<T, "prop">]: PartialProperties<T, "prop">[P]; };
|
||||
}>(a: T): PartialProperties<T, "prop"> extends infer T_1 ? { [P in keyof T_1]: PartialProperties<T, "prop">[P]; } : never;
|
||||
export declare function doSomething_Expected<T extends {
|
||||
prop: string;
|
||||
}>(a: T): {
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
// @declaration: true
|
||||
// @filename: internal.ts
|
||||
export declare function usePrivateType<T extends unknown[]>(...args: T): PrivateMapped<T[any]>;
|
||||
|
||||
type PrivateMapped<Obj> = {[K in keyof Obj]: Obj[K]};
|
||||
|
||||
// @filename: api.ts
|
||||
import {usePrivateType} from './internal';
|
||||
export const mappedUnionWithPrivateType = <T extends unknown[]>(...args: T) => usePrivateType(...args);
|
||||
Loading…
x
Reference in New Issue
Block a user