mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-16 15:45:27 -05:00
Preserve the distributivity of inlined conditional types in declaration emit (#48592)
This commit is contained in:
@@ -5102,13 +5102,49 @@ namespace ts {
|
||||
|
||||
function conditionalTypeToTypeNode(type: ConditionalType) {
|
||||
const checkTypeNode = typeToTypeNodeHelper(type.checkType, context);
|
||||
context.approximateLength += 15;
|
||||
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive && !(type.checkType.flags & TypeFlags.TypeParameter)) {
|
||||
const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String));
|
||||
const name = typeParameterToName(newParam, context);
|
||||
const newTypeVariable = factory.createTypeReferenceNode(name);
|
||||
context.approximateLength += 37; // 15 each for two added conditionals, 7 for an added infer type
|
||||
const newMapper = prependTypeMapping(type.root.checkType, newParam, type.combinedMapper || type.mapper);
|
||||
const saveInferTypeParameters = context.inferTypeParameters;
|
||||
context.inferTypeParameters = type.root.inferTypeParameters;
|
||||
const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context);
|
||||
context.inferTypeParameters = saveInferTypeParameters;
|
||||
const trueTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper));
|
||||
const falseTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper));
|
||||
|
||||
|
||||
// outermost conditional makes `T` a type parameter, allowing the inner conditionals to be distributive
|
||||
// second conditional makes `T` have `T & checkType` substitution, so it is correctly usable as the checkType
|
||||
// inner conditional runs the check the user provided on the check type (distributively) and returns the result
|
||||
// checkType extends infer T ? T extends checkType ? T extends extendsType<T> ? trueType<T> : falseType<T> : never : never;
|
||||
// this is potentially simplifiable to
|
||||
// checkType extends infer T ? T extends checkType & extendsType<T> ? trueType<T> : falseType<T> : never;
|
||||
// but that may confuse users who read the output more.
|
||||
// On the other hand,
|
||||
// checkType extends infer T extends checkType ? T extends extendsType<T> ? trueType<T> : falseType<T> : never;
|
||||
// may also work with `infer ... extends ...` in, but would produce declarations only compatible with the latest TS.
|
||||
return factory.createConditionalTypeNode(
|
||||
checkTypeNode,
|
||||
factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable.typeName) as Identifier)),
|
||||
factory.createConditionalTypeNode(
|
||||
factory.createTypeReferenceNode(factory.cloneNode(name)),
|
||||
typeToTypeNodeHelper(type.checkType, context),
|
||||
factory.createConditionalTypeNode(newTypeVariable, extendsTypeNode, trueTypeNode, falseTypeNode),
|
||||
factory.createKeywordTypeNode(SyntaxKind.NeverKeyword)
|
||||
),
|
||||
factory.createKeywordTypeNode(SyntaxKind.NeverKeyword)
|
||||
);
|
||||
}
|
||||
const saveInferTypeParameters = context.inferTypeParameters;
|
||||
context.inferTypeParameters = type.root.inferTypeParameters;
|
||||
const extendsTypeNode = typeToTypeNodeHelper(type.extendsType, context);
|
||||
context.inferTypeParameters = saveInferTypeParameters;
|
||||
const trueTypeNode = typeToTypeNodeOrCircularityElision(getTrueTypeFromConditionalType(type));
|
||||
const falseTypeNode = typeToTypeNodeOrCircularityElision(getFalseTypeFromConditionalType(type));
|
||||
context.approximateLength += 15;
|
||||
return factory.createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user