mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Check for keyof constraint type instead of syntactic check (#24098)
* Check for keyof constraint type instead of syntactic check * Readopt older candidateType check, even though it shouldnt really matter * OK. Just use maybetypeOfKind * Remove redundant boolean check
This commit is contained in:
parent
8b8cd31784
commit
0102f8050c
@ -20640,15 +20640,6 @@ namespace ts {
|
||||
return widened;
|
||||
}
|
||||
|
||||
function isTypeParameterWithKeyofConstraint(type: Type) {
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
const constraintDeclaration = getConstraintDeclaration(<TypeParameter>type);
|
||||
return constraintDeclaration && constraintDeclaration.kind === SyntaxKind.TypeOperator &&
|
||||
(<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLiteralOfContextualType(candidateType: Type, contextualType: Type | undefined): boolean {
|
||||
if (contextualType) {
|
||||
if (contextualType.flags & TypeFlags.UnionOrIntersection) {
|
||||
@ -20660,11 +20651,9 @@ namespace ts {
|
||||
// this a literal context for literals of that primitive type. For example, given a
|
||||
// type parameter 'T extends string', infer string literal types for T.
|
||||
const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
|
||||
return isTypeParameterWithKeyofConstraint(contextualType) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.UniqueESSymbol) ||
|
||||
constraint.flags & TypeFlags.String && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
|
||||
constraint.flags & TypeFlags.Number && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
|
||||
constraint.flags & TypeFlags.Boolean && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) ||
|
||||
constraint.flags & TypeFlags.ESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) ||
|
||||
return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
|
||||
maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
|
||||
maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) ||
|
||||
isLiteralOfContextualType(candidateType, constraint);
|
||||
}
|
||||
// If the contextual type is a literal of a particular primitive type, we consider this a
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
//// [jsxInferenceProducesLiteralAsExpected.tsx]
|
||||
import React = require("react");
|
||||
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
|
||||
class TestObject {
|
||||
a: string = '';
|
||||
b: number = 1;
|
||||
c: () => void = () => { };
|
||||
}
|
||||
interface TestProps<T> {
|
||||
model: T;
|
||||
foo: FunctionPropertyNames<T>;
|
||||
}
|
||||
function Test<T>(props: TestProps<T>) { return <></>; }
|
||||
const model = new TestObject();
|
||||
|
||||
const el1 = <Test model={model} foo="c" />;
|
||||
const el2 = <Test<TestObject> model={model} foo="c" />;
|
||||
|
||||
//// [jsxInferenceProducesLiteralAsExpected.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var React = require("react");
|
||||
var TestObject = /** @class */ (function () {
|
||||
function TestObject() {
|
||||
this.a = '';
|
||||
this.b = 1;
|
||||
this.c = function () { };
|
||||
}
|
||||
return TestObject;
|
||||
}());
|
||||
function Test(props) { return React.createElement(React.Fragment, null); }
|
||||
var model = new TestObject();
|
||||
var el1 = React.createElement(Test, { model: model, foo: "c" });
|
||||
var el2 = React.createElement(Test, { model: model, foo: "c" });
|
||||
@ -0,0 +1,66 @@
|
||||
=== tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx ===
|
||||
import React = require("react");
|
||||
>React : Symbol(React, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 0, 0))
|
||||
|
||||
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
|
||||
>FunctionPropertyNames : Symbol(FunctionPropertyNames, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 0, 32))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 27))
|
||||
>K : Symbol(K, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 35))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 27))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 27))
|
||||
>K : Symbol(K, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 35))
|
||||
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>K : Symbol(K, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 35))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 27))
|
||||
|
||||
class TestObject {
|
||||
>TestObject : Symbol(TestObject, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 95))
|
||||
|
||||
a: string = '';
|
||||
>a : Symbol(TestObject.a, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 2, 18))
|
||||
|
||||
b: number = 1;
|
||||
>b : Symbol(TestObject.b, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 3, 19))
|
||||
|
||||
c: () => void = () => { };
|
||||
>c : Symbol(TestObject.c, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 4, 18))
|
||||
}
|
||||
interface TestProps<T> {
|
||||
>TestProps : Symbol(TestProps, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 6, 1))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 7, 20))
|
||||
|
||||
model: T;
|
||||
>model : Symbol(TestProps.model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 7, 24))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 7, 20))
|
||||
|
||||
foo: FunctionPropertyNames<T>;
|
||||
>foo : Symbol(TestProps.foo, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 8, 13))
|
||||
>FunctionPropertyNames : Symbol(FunctionPropertyNames, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 0, 32))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 7, 20))
|
||||
}
|
||||
function Test<T>(props: TestProps<T>) { return <></>; }
|
||||
>Test : Symbol(Test, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 10, 1))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 11, 14))
|
||||
>props : Symbol(props, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 11, 17))
|
||||
>TestProps : Symbol(TestProps, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 6, 1))
|
||||
>T : Symbol(T, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 11, 14))
|
||||
|
||||
const model = new TestObject();
|
||||
>model : Symbol(model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 12, 5))
|
||||
>TestObject : Symbol(TestObject, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 95))
|
||||
|
||||
const el1 = <Test model={model} foo="c" />;
|
||||
>el1 : Symbol(el1, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 14, 5))
|
||||
>Test : Symbol(Test, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 10, 1))
|
||||
>model : Symbol(model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 14, 17))
|
||||
>model : Symbol(model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 12, 5))
|
||||
>foo : Symbol(foo, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 14, 31))
|
||||
|
||||
const el2 = <Test<TestObject> model={model} foo="c" />;
|
||||
>el2 : Symbol(el2, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 15, 5))
|
||||
>Test : Symbol(Test, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 10, 1))
|
||||
>TestObject : Symbol(TestObject, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 1, 95))
|
||||
>model : Symbol(model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 15, 29))
|
||||
>model : Symbol(model, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 12, 5))
|
||||
>foo : Symbol(foo, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 15, 43))
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
=== tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx ===
|
||||
import React = require("react");
|
||||
>React : typeof React
|
||||
|
||||
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
|
||||
>FunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]
|
||||
>T : T
|
||||
>K : K
|
||||
>T : T
|
||||
>T : T
|
||||
>K : K
|
||||
>Function : Function
|
||||
>K : K
|
||||
>T : T
|
||||
|
||||
class TestObject {
|
||||
>TestObject : TestObject
|
||||
|
||||
a: string = '';
|
||||
>a : string
|
||||
>'' : ""
|
||||
|
||||
b: number = 1;
|
||||
>b : number
|
||||
>1 : 1
|
||||
|
||||
c: () => void = () => { };
|
||||
>c : () => void
|
||||
>() => { } : () => void
|
||||
}
|
||||
interface TestProps<T> {
|
||||
>TestProps : TestProps<T>
|
||||
>T : T
|
||||
|
||||
model: T;
|
||||
>model : T
|
||||
>T : T
|
||||
|
||||
foo: FunctionPropertyNames<T>;
|
||||
>foo : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]
|
||||
>FunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]
|
||||
>T : T
|
||||
}
|
||||
function Test<T>(props: TestProps<T>) { return <></>; }
|
||||
>Test : <T>(props: TestProps<T>) => JSX.Element
|
||||
>T : T
|
||||
>props : TestProps<T>
|
||||
>TestProps : TestProps<T>
|
||||
>T : T
|
||||
><></> : JSX.Element
|
||||
|
||||
const model = new TestObject();
|
||||
>model : TestObject
|
||||
>new TestObject() : TestObject
|
||||
>TestObject : typeof TestObject
|
||||
|
||||
const el1 = <Test model={model} foo="c" />;
|
||||
>el1 : JSX.Element
|
||||
><Test model={model} foo="c" /> : JSX.Element
|
||||
>Test : <T>(props: TestProps<T>) => JSX.Element
|
||||
>model : TestObject
|
||||
>model : TestObject
|
||||
>foo : "c"
|
||||
|
||||
const el2 = <Test<TestObject> model={model} foo="c" />;
|
||||
>el2 : JSX.Element
|
||||
><Test<TestObject> model={model} foo="c" /> : JSX.Element
|
||||
>Test : <T>(props: TestProps<T>) => JSX.Element
|
||||
>TestObject : TestObject
|
||||
>model : TestObject
|
||||
>model : TestObject
|
||||
>foo : "c"
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
// @jsx: react
|
||||
// @libFiles: lib.d.ts,react.d.ts
|
||||
import React = require("react");
|
||||
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
|
||||
class TestObject {
|
||||
a: string = '';
|
||||
b: number = 1;
|
||||
c: () => void = () => { };
|
||||
}
|
||||
interface TestProps<T> {
|
||||
model: T;
|
||||
foo: FunctionPropertyNames<T>;
|
||||
}
|
||||
function Test<T>(props: TestProps<T>) { return <></>; }
|
||||
const model = new TestObject();
|
||||
|
||||
const el1 = <Test model={model} foo="c" />;
|
||||
const el2 = <Test<TestObject> model={model} foo="c" />;
|
||||
Loading…
x
Reference in New Issue
Block a user