mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
rework non-primitive restriction to be based on conditional type branches
This commit is contained in:
parent
ab0d43c8e5
commit
a7c683903d
@ -20423,7 +20423,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const checkType = root.checkType;
|
||||
let distributionType = root.isDistributive ? getReducedType(getMappedType(checkType, newMapper)) : undefined;
|
||||
let narrowingBaseType: Type | undefined;
|
||||
const forNarrowing = distributionType && isNarrowingSubstitutionType(distributionType) && isNarrowableConditionalType(type, mapper);
|
||||
const forNarrowing = distributionType &&
|
||||
isNarrowingSubstitutionType(distributionType) &&
|
||||
isNarrowableConditionalType(type, /*hadNonPrimitiveExtendsType*/ [], mapper);
|
||||
if (forNarrowing) {
|
||||
narrowingBaseType = (distributionType as SubstitutionType).baseType;
|
||||
distributionType = getReducedType((distributionType as SubstitutionType).constraint);
|
||||
@ -45985,14 +45987,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
type NarrowableReference = Identifier | ElementAccessExpression | PropertyAccessExpression;
|
||||
/**
|
||||
* Narrowable type parameters are type parameters that:
|
||||
* (1) have a narrowable constraint;
|
||||
* (1) have a union constraint;
|
||||
* (2) are syntactically used as the type of a single parameter in the function, and nothing else
|
||||
*/
|
||||
function getNarrowableTypeParameters(candidates: TypeParameter[]): [TypeParameter, Symbol, NarrowableReference][] {
|
||||
const narrowableParams: [TypeParameter, Symbol, NarrowableReference][] = [];
|
||||
for (const typeParam of candidates) {
|
||||
const constraint = getConstraintOfTypeParameter(typeParam);
|
||||
if (!constraint || !isNarrowableTypeParameterConstraint(constraint)) continue;
|
||||
if (!constraint || !(constraint.flags & TypeFlags.Union)) 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;
|
||||
@ -46068,11 +46070,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const typeArgs = (typeNode as TypeReferenceNode).typeArguments;
|
||||
// Type arguments that reference `T`
|
||||
const typeArgsReferencingT = typeArgs?.filter(node => isTypeParameterReferenced(typeParam, node));
|
||||
if (!typeArgsReferencingT || typeArgsReferencingT.length == 0) return true; // Type reference unrelated to `T`
|
||||
if (!typeArgsReferencingT || typeArgsReferencingT.length === 0) return true; // Type reference unrelated to `T`
|
||||
if (typeArgsReferencingT && typeArgsReferencingT.length > 1) return false; // e.g. `Foo<T, T, ...>`
|
||||
const typeArg = typeArgsReferencingT[0];
|
||||
if (!(typeArg.kind & SyntaxKind.TypeReference)) return false; // e.g. `Foo<Wrapper<T>, ...>`
|
||||
if (!type.symbol || !type.symbol.declarations || type.symbol.declarations.length != 1) return false;
|
||||
if (!type.symbol || !type.symbol.declarations || type.symbol.declarations.length !== 1) return false;
|
||||
const typeDeclaration = type.symbol.declarations[0];
|
||||
let aliasDeclaration;
|
||||
if (isTypeLiteralNode(typeDeclaration)) {
|
||||
@ -46243,30 +46245,13 @@ 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)
|
||||
? isNarrowableConditionalType(returnType, /*hadNonPrimitiveExtendsType*/ [])
|
||||
: !!(returnType.indexType.flags & TypeFlags.TypeParameter);
|
||||
}
|
||||
|
||||
function isNarrowableConditionalType(type: ConditionalType, mapper?: TypeMapper): boolean {
|
||||
function isNarrowableConditionalType(type: ConditionalType, hadNonPrimitiveExtendsType: TypeParameter[], mapper?: TypeMapper): boolean {
|
||||
const typeArguments = mapper && map(type.root.outerTypeParameters, t => {
|
||||
const mapped = getMappedType(t, mapper);
|
||||
if (isNarrowingSubstitutionType(mapped)) {
|
||||
@ -46274,14 +46259,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
return mapped;
|
||||
});
|
||||
const id = `${type.id}:${getTypeListId(typeArguments)}`;
|
||||
const id = `${type.id}:${getTypeListId(typeArguments)}:${getTypeListId(hadNonPrimitiveExtendsType)}`;
|
||||
let result = narrowableReturnTypeCache.get(id);
|
||||
if (result === undefined) {
|
||||
const nonNarrowingMapper = type.root.outerTypeParameters
|
||||
&& typeArguments
|
||||
&& createTypeMapper(type.root.outerTypeParameters, typeArguments);
|
||||
const instantiatedType = instantiateType(type, nonNarrowingMapper);
|
||||
result = isConditionalType(instantiatedType) && isNarrowableConditionalTypeWorker(instantiatedType);
|
||||
result = isConditionalType(instantiatedType) &&
|
||||
isNarrowableConditionalTypeWorker(instantiatedType, hadNonPrimitiveExtendsType);
|
||||
narrowableReturnTypeCache.set(id, result);
|
||||
}
|
||||
return result;
|
||||
@ -46293,9 +46279,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// (1) The conditional type has no `infer` type parameters;
|
||||
// (2) The conditional type's check type is a narrowable type parameter (i.e. a type parameter with a union constraint);
|
||||
// (3) The extends type `A` is a type or a union of types that are supertypes of the union constraint of the type parameter;
|
||||
// (4) `TrueBranch<T>` and `FalseBranch<T>` must be valid, recursively.
|
||||
// (4) At most one extends type has a non-primitive type.
|
||||
// (5) `TrueBranch<T>` and `FalseBranch<T>` must be valid, recursively.
|
||||
// In particular, the false-most branch of the conditional type must be `never`.
|
||||
function isNarrowableConditionalTypeWorker(type: ConditionalType): boolean {
|
||||
function isNarrowableConditionalTypeWorker(type: ConditionalType, hadNonPrimitiveExtendsType: TypeParameter[]): boolean {
|
||||
// (0)
|
||||
if (!type.root.isDistributive) {
|
||||
return false;
|
||||
@ -46328,14 +46315,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
// (4)
|
||||
const hasNonPrimitive = someType(type.extendsType, type => (type.flags & TypeFlags.Primitive) === 0);
|
||||
if (hasNonPrimitive && hadNonPrimitiveExtendsType.includes(type.checkType)) {
|
||||
return false;
|
||||
}
|
||||
if (hasNonPrimitive) {
|
||||
hadNonPrimitiveExtendsType = hadNonPrimitiveExtendsType.slice();
|
||||
hadNonPrimitiveExtendsType.push(type.checkType);
|
||||
}
|
||||
|
||||
// (5)
|
||||
const trueType = getTrueTypeFromConditionalType(type);
|
||||
const isValidTrueType = isConditionalType(trueType)
|
||||
? isNarrowableConditionalType(trueType)
|
||||
? isNarrowableConditionalType(trueType, hadNonPrimitiveExtendsType)
|
||||
: true;
|
||||
if (!isValidTrueType) return false;
|
||||
const falseType = getFalseTypeFromConditionalType(type);
|
||||
const isValidFalseType = isConditionalType(falseType)
|
||||
? isNarrowableConditionalType(falseType)
|
||||
? isNarrowableConditionalType(falseType, hadNonPrimitiveExtendsType)
|
||||
: falseType === neverType;
|
||||
return isValidFalseType;
|
||||
}
|
||||
|
||||
145
tests/baselines/reference/dependentReturnType13.errors.txt
Normal file
145
tests/baselines/reference/dependentReturnType13.errors.txt
Normal file
@ -0,0 +1,145 @@
|
||||
dependentReturnType13.ts(29,9): error TS2322: Type '2' is not assignable to type 'T extends string ? 1 : T extends string[] ? 2 : T extends number[] ? 3 : never'.
|
||||
dependentReturnType13.ts(31,5): error TS2322: Type '1' is not assignable to type 'T extends string ? 1 : T extends string[] ? 2 : T extends number[] ? 3 : never'.
|
||||
dependentReturnType13.ts(49,9): error TS2322: Type '2' is not assignable to type 'T extends Cat ? 1 : T extends Dog ? 2 : never'.
|
||||
dependentReturnType13.ts(52,5): error TS2322: Type '1' is not assignable to type 'T extends Cat ? 1 : T extends Dog ? 2 : never'.
|
||||
dependentReturnType13.ts(79,9): error TS2322: Type '2' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
dependentReturnType13.ts(83,13): error TS2322: Type '3' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
dependentReturnType13.ts(85,9): error TS2322: Type '1' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
dependentReturnType13.ts(88,9): error TS2322: Type '4' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
dependentReturnType13.ts(90,5): error TS2322: Type '5' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
|
||||
|
||||
==== dependentReturnType13.ts (9 errors) ====
|
||||
// Restrictions on what kind of union types can be narrowed.
|
||||
|
||||
function f1<T extends string | string[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f2<T extends string | string[] | number[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends string[] | number[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f3<T extends string | string[] | number[]>(param: T): // Bad.
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
T extends number[] ? 3 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '2' is not assignable to type 'T extends string ? 1 : T extends string[] ? 2 : T extends number[] ? 3 : never'.
|
||||
}
|
||||
return 1;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '1' is not assignable to type 'T extends string ? 1 : T extends string[] ? 2 : T extends number[] ? 3 : never'.
|
||||
}
|
||||
|
||||
class Dog {
|
||||
bark(): void {}
|
||||
}
|
||||
|
||||
class Cat {
|
||||
meow(): void {}
|
||||
|
||||
}
|
||||
|
||||
function f4<T extends Cat | Dog>(param: T): // Bad.
|
||||
T extends Cat ? 1 :
|
||||
T extends Dog ? 2 :
|
||||
never {
|
||||
if ('bark' in param) {
|
||||
const _: Dog = param;
|
||||
return 2;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '2' is not assignable to type 'T extends Cat ? 1 : T extends Dog ? 2 : never'.
|
||||
}
|
||||
const _: Cat = param;
|
||||
return 1;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '1' is not assignable to type 'T extends Cat ? 1 : T extends Dog ? 2 : never'.
|
||||
}
|
||||
|
||||
function f5<T extends string | number | string[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends number | string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param) || typeof param === "number") {
|
||||
const _: string[] | number = param;
|
||||
return 2;
|
||||
}
|
||||
const _: string = param;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f6<T extends string | number[] | string[], U extends boolean>(param: T, other: U):
|
||||
T extends number[] ? 2 :
|
||||
U extends true ?
|
||||
T extends string[] ? 3 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends false ?
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 5 :
|
||||
never :
|
||||
never {
|
||||
if (isNumberArray(param)) {
|
||||
return 2;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '2' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
}
|
||||
if (other) {
|
||||
if (Array.isArray(param)) {
|
||||
return 3;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '3' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
}
|
||||
return 1;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '1' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
return 4;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '4' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
}
|
||||
return 5;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '5' is not assignable to type 'T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never'.
|
||||
}
|
||||
|
||||
declare function isNumberArray(x: unknown): x is number[];
|
||||
|
||||
function f7<T extends string | string[], U extends number | number[]>(param: T, other: U):
|
||||
U extends number ?
|
||||
T extends string[] ? 2 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends number[] ?
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 3 :
|
||||
never :
|
||||
never {
|
||||
if (Array.isArray(other)) {
|
||||
if (Array.isArray(param)) {
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
287
tests/baselines/reference/dependentReturnType13.symbols
Normal file
287
tests/baselines/reference/dependentReturnType13.symbols
Normal file
@ -0,0 +1,287 @@
|
||||
//// [tests/cases/compiler/dependentReturnType13.ts] ////
|
||||
|
||||
=== dependentReturnType13.ts ===
|
||||
// Restrictions on what kind of union types can be narrowed.
|
||||
|
||||
function f1<T extends string | string[]>(param: T):
|
||||
>f1 : Symbol(f1, Decl(dependentReturnType13.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 2, 12))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 2, 41))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 2, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 2, 12))
|
||||
|
||||
T extends string[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 2, 12))
|
||||
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 2, 41))
|
||||
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f2<T extends string | string[] | number[]>(param: T):
|
||||
>f2 : Symbol(f2, Decl(dependentReturnType13.ts, 10, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 12, 12))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 12, 52))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 12, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 12, 12))
|
||||
|
||||
T extends string[] | number[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 12, 12))
|
||||
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 12, 52))
|
||||
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f3<T extends string | string[] | number[]>(param: T): // Bad.
|
||||
>f3 : Symbol(f3, Decl(dependentReturnType13.ts, 20, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 22, 12))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 22, 52))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 22, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 22, 12))
|
||||
|
||||
T extends string[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 22, 12))
|
||||
|
||||
T extends number[] ? 3 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 22, 12))
|
||||
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 22, 52))
|
||||
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
class Dog {
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType13.ts, 31, 1))
|
||||
|
||||
bark(): void {}
|
||||
>bark : Symbol(Dog.bark, Decl(dependentReturnType13.ts, 33, 11))
|
||||
}
|
||||
|
||||
class Cat {
|
||||
>Cat : Symbol(Cat, Decl(dependentReturnType13.ts, 35, 1))
|
||||
|
||||
meow(): void {}
|
||||
>meow : Symbol(Cat.meow, Decl(dependentReturnType13.ts, 37, 11))
|
||||
|
||||
}
|
||||
|
||||
function f4<T extends Cat | Dog>(param: T): // Bad.
|
||||
>f4 : Symbol(f4, Decl(dependentReturnType13.ts, 40, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 42, 12))
|
||||
>Cat : Symbol(Cat, Decl(dependentReturnType13.ts, 35, 1))
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType13.ts, 31, 1))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 42, 33))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 42, 12))
|
||||
|
||||
T extends Cat ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 42, 12))
|
||||
>Cat : Symbol(Cat, Decl(dependentReturnType13.ts, 35, 1))
|
||||
|
||||
T extends Dog ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 42, 12))
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType13.ts, 31, 1))
|
||||
|
||||
never {
|
||||
if ('bark' in param) {
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 42, 33))
|
||||
|
||||
const _: Dog = param;
|
||||
>_ : Symbol(_, Decl(dependentReturnType13.ts, 47, 13))
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType13.ts, 31, 1))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 42, 33))
|
||||
|
||||
return 2;
|
||||
}
|
||||
const _: Cat = param;
|
||||
>_ : Symbol(_, Decl(dependentReturnType13.ts, 50, 9))
|
||||
>Cat : Symbol(Cat, Decl(dependentReturnType13.ts, 35, 1))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 42, 33))
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f5<T extends string | number | string[]>(param: T):
|
||||
>f5 : Symbol(f5, Decl(dependentReturnType13.ts, 52, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 54, 12))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 54, 50))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 54, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 54, 12))
|
||||
|
||||
T extends number | string[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 54, 12))
|
||||
|
||||
never {
|
||||
if (Array.isArray(param) || typeof param === "number") {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 54, 50))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 54, 50))
|
||||
|
||||
const _: string[] | number = param;
|
||||
>_ : Symbol(_, Decl(dependentReturnType13.ts, 59, 13))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 54, 50))
|
||||
|
||||
return 2;
|
||||
}
|
||||
const _: string = param;
|
||||
>_ : Symbol(_, Decl(dependentReturnType13.ts, 62, 9))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 54, 50))
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f6<T extends string | number[] | string[], U extends boolean>(param: T, other: U):
|
||||
>f6 : Symbol(f6, Decl(dependentReturnType13.ts, 64, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 66, 51))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 66, 71))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
>other : Symbol(other, Decl(dependentReturnType13.ts, 66, 80))
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 66, 51))
|
||||
|
||||
T extends number[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
|
||||
U extends true ?
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 66, 51))
|
||||
|
||||
T extends string[] ? 3 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
|
||||
never :
|
||||
U extends false ?
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 66, 51))
|
||||
|
||||
T extends string[] ? 4 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
|
||||
T extends string ? 5 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 66, 12))
|
||||
|
||||
never :
|
||||
never {
|
||||
if (isNumberArray(param)) {
|
||||
>isNumberArray : Symbol(isNumberArray, Decl(dependentReturnType13.ts, 90, 1))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 66, 71))
|
||||
|
||||
return 2;
|
||||
}
|
||||
if (other) {
|
||||
>other : Symbol(other, Decl(dependentReturnType13.ts, 66, 80))
|
||||
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 66, 71))
|
||||
|
||||
return 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 66, 71))
|
||||
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
declare function isNumberArray(x: unknown): x is number[];
|
||||
>isNumberArray : Symbol(isNumberArray, Decl(dependentReturnType13.ts, 90, 1))
|
||||
>x : Symbol(x, Decl(dependentReturnType13.ts, 92, 31))
|
||||
>x : Symbol(x, Decl(dependentReturnType13.ts, 92, 31))
|
||||
|
||||
function f7<T extends string | string[], U extends number | number[]>(param: T, other: U):
|
||||
>f7 : Symbol(f7, Decl(dependentReturnType13.ts, 92, 58))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 94, 40))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 94, 70))
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
>other : Symbol(other, Decl(dependentReturnType13.ts, 94, 79))
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 94, 40))
|
||||
|
||||
U extends number ?
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 94, 40))
|
||||
|
||||
T extends string[] ? 2 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
|
||||
T extends string ? 1 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
|
||||
never :
|
||||
U extends number[] ?
|
||||
>U : Symbol(U, Decl(dependentReturnType13.ts, 94, 40))
|
||||
|
||||
T extends string[] ? 4 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
|
||||
T extends string ? 3 :
|
||||
>T : Symbol(T, Decl(dependentReturnType13.ts, 94, 12))
|
||||
|
||||
never :
|
||||
never {
|
||||
if (Array.isArray(other)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>other : Symbol(other, Decl(dependentReturnType13.ts, 94, 79))
|
||||
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 94, 70))
|
||||
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>param : Symbol(param, Decl(dependentReturnType13.ts, 94, 70))
|
||||
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
361
tests/baselines/reference/dependentReturnType13.types
Normal file
361
tests/baselines/reference/dependentReturnType13.types
Normal file
@ -0,0 +1,361 @@
|
||||
//// [tests/cases/compiler/dependentReturnType13.ts] ////
|
||||
|
||||
=== dependentReturnType13.ts ===
|
||||
// Restrictions on what kind of union types can be narrowed.
|
||||
|
||||
function f1<T extends string | string[]>(param: T):
|
||||
>f1 : <T extends string | string[]>(param: T) => T extends string ? 1 : T extends string[] ? 2 : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
|
||||
function f2<T extends string | string[] | number[]>(param: T):
|
||||
>f2 : <T extends string | string[] | number[]>(param: T) => T extends string ? 1 : T extends string[] | number[] ? 2 : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
T extends string ? 1 :
|
||||
T extends string[] | number[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[] | number[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
|
||||
function f3<T extends string | string[] | number[]>(param: T): // Bad.
|
||||
>f3 : <T extends string | string[] | number[]>(param: T) => T extends string ? 1 : T extends string[] ? 2 : T extends number[] ? 3 : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
T extends number[] ? 3 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[] | number[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
|
||||
class Dog {
|
||||
>Dog : Dog
|
||||
> : ^^^
|
||||
|
||||
bark(): void {}
|
||||
>bark : () => void
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
class Cat {
|
||||
>Cat : Cat
|
||||
> : ^^^
|
||||
|
||||
meow(): void {}
|
||||
>meow : () => void
|
||||
> : ^^^^^^
|
||||
|
||||
}
|
||||
|
||||
function f4<T extends Cat | Dog>(param: T): // Bad.
|
||||
>f4 : <T extends Cat | Dog>(param: T) => T extends Cat ? 1 : T extends Dog ? 2 : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
T extends Cat ? 1 :
|
||||
T extends Dog ? 2 :
|
||||
never {
|
||||
if ('bark' in param) {
|
||||
>'bark' in param : boolean
|
||||
> : ^^^^^^^
|
||||
>'bark' : "bark"
|
||||
> : ^^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
const _: Dog = param;
|
||||
>_ : Dog
|
||||
> : ^^^
|
||||
>param : Dog
|
||||
> : ^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
const _: Cat = param;
|
||||
>_ : Cat
|
||||
> : ^^^
|
||||
>param : Cat
|
||||
> : ^^^
|
||||
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
|
||||
function f5<T extends string | number | string[]>(param: T):
|
||||
>f5 : <T extends string | number | string[]>(param: T) => T extends string ? 1 : T extends number | string[] ? 2 : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
|
||||
T extends string ? 1 :
|
||||
T extends number | string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param) || typeof param === "number") {
|
||||
>Array.isArray(param) || typeof param === "number" : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | number | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>typeof param === "number" : boolean
|
||||
> : ^^^^^^^
|
||||
>typeof param : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
>"number" : "number"
|
||||
> : ^^^^^^^^
|
||||
|
||||
const _: string[] | number = param;
|
||||
>_ : number | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
>param : number | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
const _: string = param;
|
||||
>_ : string
|
||||
> : ^^^^^^
|
||||
>param : string
|
||||
> : ^^^^^^
|
||||
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
|
||||
function f6<T extends string | number[] | string[], U extends boolean>(param: T, other: U):
|
||||
>f6 : <T extends string | number[] | string[], U extends boolean>(param: T, other: U) => T extends number[] ? 2 : U extends true ? T extends string[] ? 3 : T extends string ? 1 : never : U extends false ? T extends string[] ? 4 : T extends string ? 5 : never : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
>other : U
|
||||
> : ^
|
||||
|
||||
T extends number[] ? 2 :
|
||||
U extends true ?
|
||||
>true : true
|
||||
> : ^^^^
|
||||
|
||||
T extends string[] ? 3 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends false ?
|
||||
>false : false
|
||||
> : ^^^^^
|
||||
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 5 :
|
||||
never :
|
||||
never {
|
||||
if (isNumberArray(param)) {
|
||||
>isNumberArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>isNumberArray : (x: unknown) => x is number[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[] | number[]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
if (other) {
|
||||
>other : U
|
||||
> : ^
|
||||
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 3;
|
||||
>3 : 3
|
||||
> : ^
|
||||
}
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 4;
|
||||
>4 : 4
|
||||
> : ^
|
||||
}
|
||||
return 5;
|
||||
>5 : 5
|
||||
> : ^
|
||||
}
|
||||
|
||||
declare function isNumberArray(x: unknown): x is number[];
|
||||
>isNumberArray : (x: unknown) => x is number[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>x : unknown
|
||||
> : ^^^^^^^
|
||||
|
||||
function f7<T extends string | string[], U extends number | number[]>(param: T, other: U):
|
||||
>f7 : <T extends string | string[], U extends number | number[]>(param: T, other: U) => U extends number ? T extends string[] ? 2 : T extends string ? 1 : never : U extends number[] ? T extends string[] ? 4 : T extends string ? 3 : never : never
|
||||
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
|
||||
>param : T
|
||||
> : ^
|
||||
>other : U
|
||||
> : ^
|
||||
|
||||
U extends number ?
|
||||
T extends string[] ? 2 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends number[] ?
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 3 :
|
||||
never :
|
||||
never {
|
||||
if (Array.isArray(other)) {
|
||||
>Array.isArray(other) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>other : number | number[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 4;
|
||||
>4 : 4
|
||||
> : ^
|
||||
}
|
||||
return 3;
|
||||
>3 : 3
|
||||
> : ^
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
>Array.isArray(param) : boolean
|
||||
> : ^^^^^^^
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>Array : ArrayConstructor
|
||||
> : ^^^^^^^^^^^^^^^^
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
> : ^ ^^ ^^^^^
|
||||
>param : string | string[]
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
> : ^
|
||||
}
|
||||
return 1;
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
119
tests/cases/compiler/dependentReturnType13.ts
Normal file
119
tests/cases/compiler/dependentReturnType13.ts
Normal file
@ -0,0 +1,119 @@
|
||||
// @noEmit: true
|
||||
// @strict: true
|
||||
|
||||
|
||||
// Restrictions on what kind of union types can be narrowed.
|
||||
|
||||
function f1<T extends string | string[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f2<T extends string | string[] | number[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends string[] | number[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f3<T extends string | string[] | number[]>(param: T): // Bad.
|
||||
T extends string ? 1 :
|
||||
T extends string[] ? 2 :
|
||||
T extends number[] ? 3 :
|
||||
never {
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
class Dog {
|
||||
bark(): void {}
|
||||
}
|
||||
|
||||
class Cat {
|
||||
meow(): void {}
|
||||
|
||||
}
|
||||
|
||||
function f4<T extends Cat | Dog>(param: T): // Bad.
|
||||
T extends Cat ? 1 :
|
||||
T extends Dog ? 2 :
|
||||
never {
|
||||
if ('bark' in param) {
|
||||
const _: Dog = param;
|
||||
return 2;
|
||||
}
|
||||
const _: Cat = param;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f5<T extends string | number | string[]>(param: T):
|
||||
T extends string ? 1 :
|
||||
T extends number | string[] ? 2 :
|
||||
never {
|
||||
if (Array.isArray(param) || typeof param === "number") {
|
||||
const _: string[] | number = param;
|
||||
return 2;
|
||||
}
|
||||
const _: string = param;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function f6<T extends string | number[] | string[], U extends boolean>(param: T, other: U):
|
||||
T extends number[] ? 2 :
|
||||
U extends true ?
|
||||
T extends string[] ? 3 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends false ?
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 5 :
|
||||
never :
|
||||
never {
|
||||
if (isNumberArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
if (other) {
|
||||
if (Array.isArray(param)) {
|
||||
return 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
declare function isNumberArray(x: unknown): x is number[];
|
||||
|
||||
function f7<T extends string | string[], U extends number | number[]>(param: T, other: U):
|
||||
U extends number ?
|
||||
T extends string[] ? 2 :
|
||||
T extends string ? 1 :
|
||||
never :
|
||||
U extends number[] ?
|
||||
T extends string[] ? 4 :
|
||||
T extends string ? 3 :
|
||||
never :
|
||||
never {
|
||||
if (Array.isArray(other)) {
|
||||
if (Array.isArray(param)) {
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (Array.isArray(param)) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user