mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
add restriction on narrowable type constraint
This commit is contained in:
+21
-3
@@ -45976,14 +45976,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
/**
|
||||
* Narrowable type parameters are type parameters that:
|
||||
* (1) have a union type constraint;
|
||||
* (2) are used as the type of a single parameter in the function, and nothing else
|
||||
* (1) have a narrowable constraint;
|
||||
* (2) are syntactically used as the type of a single parameter in the function, and nothing else
|
||||
*/
|
||||
function getNarrowableTypeParameters(candidates: TypeParameter[]): [TypeParameter, Symbol, Identifier][] {
|
||||
const narrowableParams: [TypeParameter, Symbol, Identifier][] = [];
|
||||
for (const typeParam of candidates) {
|
||||
const constraint = getConstraintOfTypeParameter(typeParam);
|
||||
if (!constraint || !(constraint.flags & TypeFlags.Union)) continue;
|
||||
if (!constraint || !isNarrowableTypeParameterConstraint(constraint)) continue;
|
||||
if (typeParam.symbol && typeParam.symbol.declarations && typeParam.symbol.declarations.length === 1) {
|
||||
const declaration = typeParam.symbol.declarations[0];
|
||||
const container = isJSDocTemplateTag(declaration.parent) ? getJSDocHost(declaration.parent) : declaration.parent;
|
||||
@@ -46050,6 +46050,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the type parameter constraint allows for narrowing of that type parameter.
|
||||
* This is true if:
|
||||
* (1) the constraint is a union type;
|
||||
* (2) there's at most one non-primitive type in the union.
|
||||
*/
|
||||
function isNarrowableTypeParameterConstraint(constraint: Type): boolean {
|
||||
if (!(constraint.flags & TypeFlags.Union)) return false;
|
||||
let nonPrimitives = 0;
|
||||
for (const type of (constraint as UnionType).types) {
|
||||
if (!(type.flags & TypeFlags.Primitive)) {
|
||||
nonPrimitives += 1;
|
||||
}
|
||||
}
|
||||
return nonPrimitives <= 1;
|
||||
}
|
||||
|
||||
function isNarrowableReturnType(returnType: IndexedAccessType | ConditionalType): boolean {
|
||||
return isConditionalType(returnType)
|
||||
? isNarrowableConditionalType(returnType)
|
||||
|
||||
@@ -22,6 +22,8 @@ dependentReturnType1.ts(206,28): error TS2322: Type 'number' is not assignable t
|
||||
dependentReturnType1.ts(243,9): error TS2322: Type '""' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'.
|
||||
dependentReturnType1.ts(245,9): error TS2322: Type 'true' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'.
|
||||
dependentReturnType1.ts(247,5): error TS2322: Type '3' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'.
|
||||
dependentReturnType1.ts(258,9): error TS2322: Type 'string' is not assignable to type 'T extends { a: string; } ? number : T extends { b: number; } ? string : never'.
|
||||
dependentReturnType1.ts(261,5): error TS2322: Type 'number' is not assignable to type 'T extends { a: string; } ? number : T extends { b: number; } ? string : never'.
|
||||
dependentReturnType1.ts(275,9): error TS2322: Type '1' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'.
|
||||
dependentReturnType1.ts(278,9): error TS2322: Type '2' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'.
|
||||
dependentReturnType1.ts(280,5): error TS2322: Type '0' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'.
|
||||
@@ -44,7 +46,7 @@ dependentReturnType1.ts(488,9): error TS2322: Type 'R' is not assignable to type
|
||||
dependentReturnType1.ts(514,5): error TS2322: Type '1' is not assignable to type 'never'.
|
||||
|
||||
|
||||
==== dependentReturnType1.ts (39 errors) ====
|
||||
==== dependentReturnType1.ts (41 errors) ====
|
||||
interface A {
|
||||
1: number;
|
||||
2: string;
|
||||
@@ -346,9 +348,13 @@ dependentReturnType1.ts(514,5): error TS2322: Type '1' is not assignable to type
|
||||
if (q(x)) {
|
||||
x.b;
|
||||
return "";
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'T extends { a: string; } ? number : T extends { b: number; } ? string : never'.
|
||||
}
|
||||
x.a;
|
||||
return 1;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'T extends { a: string; } ? number : T extends { b: number; } ? string : never'.
|
||||
}
|
||||
|
||||
let y = { a: "", b: 1 }
|
||||
|
||||
Reference in New Issue
Block a user