-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Preserve type parameter constraint in emitted mapped types while preserving their distributivity #54759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
weswigham
merged 11 commits into
microsoft:main
from
Andarist:fix/mapped-type-dts-emit-type-param-constraint
May 12, 2025
Merged
Preserve type parameter constraint in emitted mapped types while preserving their distributivity #54759
Changes from 2 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
bfdd0d9
Preserve type parameter constraint in emitted mapped types while pres…
Andarist 3cf7cea
Add extra test case
Andarist cc288b6
Merge remote-tracking branch 'origin/main' into fix/mapped-type-dts-e…
Andarist eb0e1e0
reuse typeParameter symbol
Andarist b618196
Merge remote-tracking branch 'origin/main' into fix/mapped-type-dts-e…
Andarist 2e29ffe
Merge remote-tracking branch 'origin/main' into fix/mapped-type-dts-e…
Andarist 502e988
Merge remote-tracking branch 'origin/main' into fix/mapped-type-dts-e…
Andarist ad311b5
just use `cloneTypeParameter`
Andarist 9a78b3d
Merge remote-tracking branch 'origin/main' into fix/mapped-type-dts-e…
Andarist 0fd66de
address PR feedback
Andarist f8a26fb
wrap only necessary nodes
Andarist File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6638,22 +6638,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | |
const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined; | ||
let appropriateConstraintTypeNode: TypeNode; | ||
let newTypeVariable: TypeReferenceNode | undefined; | ||
let templateType = getTemplateTypeFromMappedType(type); | ||
let typeParameter = getTypeParameterFromMappedType(type); | ||
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` | ||
if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { | ||
const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); | ||
const name = typeParameterToName(newParam, context); | ||
const newConstraintParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); | ||
const newTypeParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "K" as __String)); | ||
const name = typeParameterToName(newConstraintParam, context); | ||
const target = type.target as MappedType; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...This is probably more elegant than using a |
||
typeParameter = newTypeParam; | ||
newTypeVariable = factory.createTypeReferenceNode(name); | ||
templateType = instantiateType( | ||
getTemplateTypeFromMappedType(target), | ||
makeArrayTypeMapper([getTypeParameterFromMappedType(target), getModifiersTypeFromMappedType(target)], [newTypeParam, newConstraintParam]) | ||
); | ||
} | ||
appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)); | ||
} | ||
else { | ||
appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context); | ||
} | ||
const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); | ||
const typeParameterNode = typeParameterToDeclarationWithConstraint(typeParameter, context, appropriateConstraintTypeNode); | ||
const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; | ||
const templateTypeNode = typeToTypeNodeHelper(removeMissingType(getTemplateTypeFromMappedType(type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); | ||
const templateTypeNode = typeToTypeNodeHelper(removeMissingType(templateType, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); | ||
const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined); | ||
context.approximateLength += 10; | ||
const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
tests/baselines/reference/declarationEmitMappedTypePreservesTypeParameterConstraint.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
//// [tests/cases/compiler/declarationEmitMappedTypePreservesTypeParameterConstraint.ts] //// | ||
|
||
//// [declarationEmitMappedTypePreservesTypeParameterConstraint.ts] | ||
// repro from https://github.com/microsoft/TypeScript/issues/54560 | ||
|
||
declare type requiredKeys<T extends object> = { | ||
[k in keyof T]: undefined extends T[k] ? never : k; | ||
}[keyof T]; | ||
|
||
declare type addQuestionMarks< | ||
T extends object, | ||
R extends keyof T = requiredKeys<T> | ||
> = Pick<Required<T>, R> & Partial<T>; | ||
|
||
declare type identity<T> = T; | ||
|
||
declare type flatten<T> = identity<{ | ||
[k in keyof T]: T[k]; | ||
}>; | ||
|
||
export declare abstract class ZodType<Output = any> { | ||
readonly _output: Output; | ||
} | ||
|
||
export declare class ZodLiteral<T> extends ZodType<T> {} | ||
|
||
export declare type ZodTypeAny = ZodType<any>; | ||
|
||
export declare type baseObjectOutputType<Shape extends ZodRawShape> = { | ||
[k in keyof Shape]: Shape[k]["_output"]; | ||
}; | ||
|
||
export declare type objectOutputType<Shape extends ZodRawShape> = flatten< | ||
addQuestionMarks<baseObjectOutputType<Shape>> | ||
>; | ||
|
||
export declare type ZodRawShape = { | ||
[k: string]: ZodTypeAny; | ||
}; | ||
|
||
export const buildSchema = <V extends string>( | ||
version: V | ||
): objectOutputType<{ | ||
version: ZodLiteral<V>; | ||
}> => ({} as any); | ||
|
||
// repro from https://github.com/microsoft/TypeScript/issues/55049 | ||
|
||
type evaluate<t> = { [k in keyof t]: t[k] } & unknown | ||
|
||
export type entryOf<o> = evaluate< | ||
{ [k in keyof o]-?: [k, o[k] & ({} | null)] }[o extends readonly unknown[] | ||
? keyof o & number | ||
: keyof o] | ||
> | ||
|
||
export type entriesOf<o extends object> = evaluate<entryOf<o>[]> | ||
|
||
export const entriesOf = <o extends object>(o: o) => | ||
Object.entries(o) as entriesOf<o> | ||
|
||
|
||
//// [declarationEmitMappedTypePreservesTypeParameterConstraint.js] | ||
"use strict"; | ||
// repro from https://github.com/microsoft/TypeScript/issues/54560 | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.entriesOf = exports.buildSchema = void 0; | ||
var buildSchema = function (version) { return ({}); }; | ||
exports.buildSchema = buildSchema; | ||
var entriesOf = function (o) { | ||
return Object.entries(o); | ||
}; | ||
exports.entriesOf = entriesOf; | ||
|
||
|
||
//// [declarationEmitMappedTypePreservesTypeParameterConstraint.d.ts] | ||
declare type requiredKeys<T extends object> = { | ||
[k in keyof T]: undefined extends T[k] ? never : k; | ||
}[keyof T]; | ||
declare type addQuestionMarks<T extends object, R extends keyof T = requiredKeys<T>> = Pick<Required<T>, R> & Partial<T>; | ||
declare type identity<T> = T; | ||
declare type flatten<T> = identity<{ | ||
[k in keyof T]: T[k]; | ||
}>; | ||
export declare abstract class ZodType<Output = any> { | ||
readonly _output: Output; | ||
} | ||
export declare class ZodLiteral<T> extends ZodType<T> { | ||
} | ||
export declare type ZodTypeAny = ZodType<any>; | ||
export declare type baseObjectOutputType<Shape extends ZodRawShape> = { | ||
[k in keyof Shape]: Shape[k]["_output"]; | ||
}; | ||
export declare type objectOutputType<Shape extends ZodRawShape> = flatten<addQuestionMarks<baseObjectOutputType<Shape>>>; | ||
export declare type ZodRawShape = { | ||
[k: string]: ZodTypeAny; | ||
}; | ||
export declare const buildSchema: <V extends string>(version: V) => addQuestionMarks<baseObjectOutputType<{ | ||
version: ZodLiteral<V>; | ||
}>, undefined extends V ? never : "version"> extends infer T ? { [K in keyof T]: T[K]; } : never; | ||
type evaluate<t> = { | ||
[k in keyof t]: t[k]; | ||
} & unknown; | ||
export type entryOf<o> = evaluate<{ | ||
[k in keyof o]-?: [k, o[k] & ({} | null)]; | ||
}[o extends readonly unknown[] ? keyof o & number : keyof o]>; | ||
export type entriesOf<o extends object> = evaluate<entryOf<o>[]>; | ||
export declare const entriesOf: <o extends object>(o: o) => ({ [k in keyof o]-?: [k, o[k] & ({} | null)]; }[o extends readonly unknown[] ? keyof o & number : keyof o] extends infer T ? { [K in keyof T]: T[K]; } : never)[]; | ||
export {}; |
181 changes: 181 additions & 0 deletions
181
tests/baselines/reference/declarationEmitMappedTypePreservesTypeParameterConstraint.symbols
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
//// [tests/cases/compiler/declarationEmitMappedTypePreservesTypeParameterConstraint.ts] //// | ||
|
||
=== declarationEmitMappedTypePreservesTypeParameterConstraint.ts === | ||
// repro from https://github.com/microsoft/TypeScript/issues/54560 | ||
|
||
declare type requiredKeys<T extends object> = { | ||
>requiredKeys : Symbol(requiredKeys, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 0, 0)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 2, 26)) | ||
|
||
[k in keyof T]: undefined extends T[k] ? never : k; | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 3, 3)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 2, 26)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 2, 26)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 3, 3)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 3, 3)) | ||
|
||
}[keyof T]; | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 2, 26)) | ||
|
||
declare type addQuestionMarks< | ||
>addQuestionMarks : Symbol(addQuestionMarks, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 4, 11)) | ||
|
||
T extends object, | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 6, 30)) | ||
|
||
R extends keyof T = requiredKeys<T> | ||
>R : Symbol(R, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 7, 19)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 6, 30)) | ||
>requiredKeys : Symbol(requiredKeys, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 0, 0)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 6, 30)) | ||
|
||
> = Pick<Required<T>, R> & Partial<T>; | ||
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) | ||
>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 6, 30)) | ||
>R : Symbol(R, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 7, 19)) | ||
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 6, 30)) | ||
|
||
declare type identity<T> = T; | ||
>identity : Symbol(identity, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 9, 38)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 11, 22)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 11, 22)) | ||
|
||
declare type flatten<T> = identity<{ | ||
>flatten : Symbol(flatten, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 11, 29)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 13, 21)) | ||
>identity : Symbol(identity, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 9, 38)) | ||
|
||
[k in keyof T]: T[k]; | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 14, 3)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 13, 21)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 13, 21)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 14, 3)) | ||
|
||
}>; | ||
|
||
export declare abstract class ZodType<Output = any> { | ||
>ZodType : Symbol(ZodType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 15, 3)) | ||
>Output : Symbol(Output, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 17, 38)) | ||
|
||
readonly _output: Output; | ||
>_output : Symbol(ZodType._output, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 17, 53)) | ||
>Output : Symbol(Output, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 17, 38)) | ||
} | ||
|
||
export declare class ZodLiteral<T> extends ZodType<T> {} | ||
>ZodLiteral : Symbol(ZodLiteral, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 19, 1)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 21, 32)) | ||
>ZodType : Symbol(ZodType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 15, 3)) | ||
>T : Symbol(T, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 21, 32)) | ||
|
||
export declare type ZodTypeAny = ZodType<any>; | ||
>ZodTypeAny : Symbol(ZodTypeAny, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 21, 56)) | ||
>ZodType : Symbol(ZodType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 15, 3)) | ||
|
||
export declare type baseObjectOutputType<Shape extends ZodRawShape> = { | ||
>baseObjectOutputType : Symbol(baseObjectOutputType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 23, 46)) | ||
>Shape : Symbol(Shape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 25, 41)) | ||
>ZodRawShape : Symbol(ZodRawShape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 31, 2)) | ||
|
||
[k in keyof Shape]: Shape[k]["_output"]; | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 26, 3)) | ||
>Shape : Symbol(Shape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 25, 41)) | ||
>Shape : Symbol(Shape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 25, 41)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 26, 3)) | ||
|
||
}; | ||
|
||
export declare type objectOutputType<Shape extends ZodRawShape> = flatten< | ||
>objectOutputType : Symbol(objectOutputType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 27, 2)) | ||
>Shape : Symbol(Shape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 29, 37)) | ||
>ZodRawShape : Symbol(ZodRawShape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 31, 2)) | ||
>flatten : Symbol(flatten, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 11, 29)) | ||
|
||
addQuestionMarks<baseObjectOutputType<Shape>> | ||
>addQuestionMarks : Symbol(addQuestionMarks, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 4, 11)) | ||
>baseObjectOutputType : Symbol(baseObjectOutputType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 23, 46)) | ||
>Shape : Symbol(Shape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 29, 37)) | ||
|
||
>; | ||
|
||
export declare type ZodRawShape = { | ||
>ZodRawShape : Symbol(ZodRawShape, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 31, 2)) | ||
|
||
[k: string]: ZodTypeAny; | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 34, 3)) | ||
>ZodTypeAny : Symbol(ZodTypeAny, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 21, 56)) | ||
|
||
}; | ||
|
||
export const buildSchema = <V extends string>( | ||
>buildSchema : Symbol(buildSchema, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 37, 12)) | ||
>V : Symbol(V, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 37, 28)) | ||
|
||
version: V | ||
>version : Symbol(version, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 37, 46)) | ||
>V : Symbol(V, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 37, 28)) | ||
|
||
): objectOutputType<{ | ||
>objectOutputType : Symbol(objectOutputType, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 27, 2)) | ||
|
||
version: ZodLiteral<V>; | ||
>version : Symbol(version, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 39, 21)) | ||
>ZodLiteral : Symbol(ZodLiteral, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 19, 1)) | ||
>V : Symbol(V, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 37, 28)) | ||
|
||
}> => ({} as any); | ||
|
||
// repro from https://github.com/microsoft/TypeScript/issues/55049 | ||
|
||
type evaluate<t> = { [k in keyof t]: t[k] } & unknown | ||
>evaluate : Symbol(evaluate, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 41, 18)) | ||
>t : Symbol(t, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 14)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 22)) | ||
>t : Symbol(t, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 14)) | ||
>t : Symbol(t, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 14)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 22)) | ||
|
||
export type entryOf<o> = evaluate< | ||
>entryOf : Symbol(entryOf, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 53)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
>evaluate : Symbol(evaluate, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 41, 18)) | ||
|
||
{ [k in keyof o]-?: [k, o[k] & ({} | null)] }[o extends readonly unknown[] | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 48, 7)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 48, 7)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
>k : Symbol(k, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 48, 7)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
|
||
? keyof o & number | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
|
||
: keyof o] | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 47, 20)) | ||
|
||
> | ||
|
||
export type entriesOf<o extends object> = evaluate<entryOf<o>[]> | ||
>entriesOf : Symbol(entriesOf, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 51, 1), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 12)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 53, 22)) | ||
>evaluate : Symbol(evaluate, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 41, 18)) | ||
>entryOf : Symbol(entryOf, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 45, 53)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 53, 22)) | ||
|
||
export const entriesOf = <o extends object>(o: o) => | ||
>entriesOf : Symbol(entriesOf, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 51, 1), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 12)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 26), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 44)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 26), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 44)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 26), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 44)) | ||
|
||
Object.entries(o) as entriesOf<o> | ||
>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) | ||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) | ||
>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 26), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 44)) | ||
>entriesOf : Symbol(entriesOf, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 51, 1), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 12)) | ||
>o : Symbol(o, Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 26), Decl(declarationEmitMappedTypePreservesTypeParameterConstraint.ts, 55, 44)) | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, this should reuse the symbol name of the existing key type, rather than always using
K
, just in case.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it would definitely be better just to reuse the existing mapped type's key type parameter wholesale; I can't really think of why we'd need a unique copy here, and it's usually better to keep type identities minimal where possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've applied the first suggestion (reusing the symbol). I'm not exactly sure what's the expected result that I'm supposed to get here but I think I might be somewhat close using this extra diff:
git diff
but the
typeParameterToName
intypeParameterToDeclarationWithConstraint
still usesNodeBuilderFlags.GenerateNamesForShadowedTypeParams
. Even if I save those flags on the side and generate this without this generation for shadowed type params then I get the same problem withtemplateTypeNode
.Am I even on the right track here? Or did I misunderstand your suggestion? It might be worthwhile to take a look at the diff here to see how it behaves with the latest patch that I pushed out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that diff is it, it's just unfortunate that we're manufacturing new type identities basically to work around a shortcoming in scope tracking in the type parameter name serializer. I think the issue as-is that the type parameter isn't "visible" to the serializer because the
context.enclosingDeclaration
is too broad - maybe if, in addition to the patch you linked, you also temporarily overridecontext.enclosingDeclaration
with a fake scope, as insignatureToSignatureDeclarationHelper
it'd work. In fact, mapped types are basically signature scopes (with only a type parameter) - that's almost certainly what's missing, and what manufacturing a new type is just a kludge covering.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get it right:
typeParameter
here (like in the shortgit diff
posted above in the hidden details)signatureToSignatureDeclarationHelper
The second thing... doesn't look completely straightforward so tbh this might take me a longer while especially since I have some more pressing reviews to address right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second thing should be much, much easier now - just a call to
enterNewScope
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I've used
enterNewScope
now but I'm not sure how to interpret the results. At times new type parameter named were introduced, at times some became reused. Maybe I should onlyenterNewScope
in certain branches here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct - you want to
enterNewScope
around the creation of the nodes that the type parameter of the mapped type should be in scope for - which is to say thenameType
(if present), and the template.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes a lot of sense, thanks! I pushed out this change - the PR should be good to go now :)