mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-11 10:00:13 -06:00
Dont allow generic narrowing when contextually typed by a binding pattern (#44081)
This commit is contained in:
parent
493ec4cc26
commit
f414d13679
@ -24124,12 +24124,12 @@ namespace ts {
|
||||
return !!(type.flags & TypeFlags.Instantiable || type.flags & TypeFlags.UnionOrIntersection && some((<UnionOrIntersectionType>type).types, containsGenericType));
|
||||
}
|
||||
|
||||
function hasContextualTypeWithNoGenericTypes(node: Node) {
|
||||
function hasNonBindingPatternContextualTypeWithNoGenericTypes(node: Node) {
|
||||
// Computing the contextual type for a child of a JSX element involves resolving the type of the
|
||||
// element's tag name, so we exclude that here to avoid circularities.
|
||||
const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) &&
|
||||
!((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) &&
|
||||
getContextualType(node);
|
||||
getContextualType(node, ContextFlags.SkipBindingPatterns);
|
||||
return contextualType && !someType(contextualType, containsGenericType);
|
||||
}
|
||||
|
||||
@ -24143,7 +24143,7 @@ namespace ts {
|
||||
// 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'.
|
||||
const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) &&
|
||||
someType(type, isGenericTypeWithUnionConstraint) &&
|
||||
(isConstraintPosition(reference) || hasContextualTypeWithNoGenericTypes(reference));
|
||||
(isConstraintPosition(reference) || hasNonBindingPatternContextualTypeWithNoGenericTypes(reference));
|
||||
return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
//// [genericObjectSpreadResultInSwitch.ts]
|
||||
type Params = {
|
||||
foo: string;
|
||||
} & ({ tag: 'a'; type: number } | { tag: 'b'; type: string });
|
||||
|
||||
const getType = <P extends Params>(params: P) => {
|
||||
const {
|
||||
// Omit
|
||||
foo,
|
||||
|
||||
...rest
|
||||
} = params;
|
||||
|
||||
return rest;
|
||||
};
|
||||
|
||||
declare const params: Params;
|
||||
|
||||
switch (params.tag) {
|
||||
case 'a': {
|
||||
// TS 4.2: number
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// TS 4.2: string
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//// [genericObjectSpreadResultInSwitch.js]
|
||||
var __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
var getType = function (params) {
|
||||
var
|
||||
// Omit
|
||||
foo = params.foo, rest = __rest(params, ["foo"]);
|
||||
return rest;
|
||||
};
|
||||
switch (params.tag) {
|
||||
case 'a': {
|
||||
// TS 4.2: number
|
||||
// TS 4.3: string | number
|
||||
var result = getType(params).type;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// TS 4.2: string
|
||||
// TS 4.3: string | number
|
||||
var result = getType(params).type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
=== tests/cases/compiler/genericObjectSpreadResultInSwitch.ts ===
|
||||
type Params = {
|
||||
>Params : Symbol(Params, Decl(genericObjectSpreadResultInSwitch.ts, 0, 0))
|
||||
|
||||
foo: string;
|
||||
>foo : Symbol(foo, Decl(genericObjectSpreadResultInSwitch.ts, 0, 15))
|
||||
|
||||
} & ({ tag: 'a'; type: number } | { tag: 'b'; type: string });
|
||||
>tag : Symbol(tag, Decl(genericObjectSpreadResultInSwitch.ts, 2, 6))
|
||||
>type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 16))
|
||||
>tag : Symbol(tag, Decl(genericObjectSpreadResultInSwitch.ts, 2, 35))
|
||||
>type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 45))
|
||||
|
||||
const getType = <P extends Params>(params: P) => {
|
||||
>getType : Symbol(getType, Decl(genericObjectSpreadResultInSwitch.ts, 4, 5))
|
||||
>P : Symbol(P, Decl(genericObjectSpreadResultInSwitch.ts, 4, 17))
|
||||
>Params : Symbol(Params, Decl(genericObjectSpreadResultInSwitch.ts, 0, 0))
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 4, 35))
|
||||
>P : Symbol(P, Decl(genericObjectSpreadResultInSwitch.ts, 4, 17))
|
||||
|
||||
const {
|
||||
// Omit
|
||||
foo,
|
||||
>foo : Symbol(foo, Decl(genericObjectSpreadResultInSwitch.ts, 5, 11))
|
||||
|
||||
...rest
|
||||
>rest : Symbol(rest, Decl(genericObjectSpreadResultInSwitch.ts, 7, 12))
|
||||
|
||||
} = params;
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 4, 35))
|
||||
|
||||
return rest;
|
||||
>rest : Symbol(rest, Decl(genericObjectSpreadResultInSwitch.ts, 7, 12))
|
||||
|
||||
};
|
||||
|
||||
declare const params: Params;
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 15, 13))
|
||||
>Params : Symbol(Params, Decl(genericObjectSpreadResultInSwitch.ts, 0, 0))
|
||||
|
||||
switch (params.tag) {
|
||||
>params.tag : Symbol(tag, Decl(genericObjectSpreadResultInSwitch.ts, 2, 6), Decl(genericObjectSpreadResultInSwitch.ts, 2, 35))
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 15, 13))
|
||||
>tag : Symbol(tag, Decl(genericObjectSpreadResultInSwitch.ts, 2, 6), Decl(genericObjectSpreadResultInSwitch.ts, 2, 35))
|
||||
|
||||
case 'a': {
|
||||
// TS 4.2: number
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
>result : Symbol(result, Decl(genericObjectSpreadResultInSwitch.ts, 21, 13))
|
||||
>getType(params).type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 16))
|
||||
>getType : Symbol(getType, Decl(genericObjectSpreadResultInSwitch.ts, 4, 5))
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 15, 13))
|
||||
>type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 16))
|
||||
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// TS 4.2: string
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
>result : Symbol(result, Decl(genericObjectSpreadResultInSwitch.ts, 28, 13))
|
||||
>getType(params).type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 45))
|
||||
>getType : Symbol(getType, Decl(genericObjectSpreadResultInSwitch.ts, 4, 5))
|
||||
>params : Symbol(params, Decl(genericObjectSpreadResultInSwitch.ts, 15, 13))
|
||||
>type : Symbol(type, Decl(genericObjectSpreadResultInSwitch.ts, 2, 45))
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
=== tests/cases/compiler/genericObjectSpreadResultInSwitch.ts ===
|
||||
type Params = {
|
||||
>Params : Params
|
||||
|
||||
foo: string;
|
||||
>foo : string
|
||||
|
||||
} & ({ tag: 'a'; type: number } | { tag: 'b'; type: string });
|
||||
>tag : "a"
|
||||
>type : number
|
||||
>tag : "b"
|
||||
>type : string
|
||||
|
||||
const getType = <P extends Params>(params: P) => {
|
||||
>getType : <P extends Params>(params: P) => Omit<P, "foo">
|
||||
><P extends Params>(params: P) => { const { // Omit foo, ...rest } = params; return rest;} : <P extends Params>(params: P) => Omit<P, "foo">
|
||||
>params : P
|
||||
|
||||
const {
|
||||
// Omit
|
||||
foo,
|
||||
>foo : string
|
||||
|
||||
...rest
|
||||
>rest : Omit<P, "foo">
|
||||
|
||||
} = params;
|
||||
>params : P
|
||||
|
||||
return rest;
|
||||
>rest : Omit<P, "foo">
|
||||
|
||||
};
|
||||
|
||||
declare const params: Params;
|
||||
>params : Params
|
||||
|
||||
switch (params.tag) {
|
||||
>params.tag : "a" | "b"
|
||||
>params : Params
|
||||
>tag : "a" | "b"
|
||||
|
||||
case 'a': {
|
||||
>'a' : "a"
|
||||
|
||||
// TS 4.2: number
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
>result : number
|
||||
>getType(params).type : number
|
||||
>getType(params) : Omit<{ foo: string; } & { tag: "a"; type: number; }, "foo">
|
||||
>getType : <P extends Params>(params: P) => Omit<P, "foo">
|
||||
>params : { foo: string; } & { tag: "a"; type: number; }
|
||||
>type : number
|
||||
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
>'b' : "b"
|
||||
|
||||
// TS 4.2: string
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
>result : string
|
||||
>getType(params).type : string
|
||||
>getType(params) : Omit<{ foo: string; } & { tag: "b"; type: string; }, "foo">
|
||||
>getType : <P extends Params>(params: P) => Omit<P, "foo">
|
||||
>params : { foo: string; } & { tag: "b"; type: string; }
|
||||
>type : string
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
|
||||
|
||||
var {...r5} = k; // Error, index
|
||||
>r5 : any
|
||||
>k : string | number | symbol
|
||||
>k : keyof T
|
||||
|
||||
var {...r6} = mapped_generic; // Error, generic mapped object type
|
||||
>r6 : { [P in keyof T]: T[P]; }
|
||||
|
||||
33
tests/cases/compiler/genericObjectSpreadResultInSwitch.ts
Normal file
33
tests/cases/compiler/genericObjectSpreadResultInSwitch.ts
Normal file
@ -0,0 +1,33 @@
|
||||
type Params = {
|
||||
foo: string;
|
||||
} & ({ tag: 'a'; type: number } | { tag: 'b'; type: string });
|
||||
|
||||
const getType = <P extends Params>(params: P) => {
|
||||
const {
|
||||
// Omit
|
||||
foo,
|
||||
|
||||
...rest
|
||||
} = params;
|
||||
|
||||
return rest;
|
||||
};
|
||||
|
||||
declare const params: Params;
|
||||
|
||||
switch (params.tag) {
|
||||
case 'a': {
|
||||
// TS 4.2: number
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// TS 4.2: string
|
||||
// TS 4.3: string | number
|
||||
const result = getType(params).type;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user