From 0102f8050c842da3e3244bf68809254e1264d3d2 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 22 May 2018 16:58:31 -0700 Subject: [PATCH] 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 --- src/compiler/checker.ts | 17 +---- .../jsxInferenceProducesLiteralAsExpected.js | 34 +++++++++ ...InferenceProducesLiteralAsExpected.symbols | 66 +++++++++++++++++ ...sxInferenceProducesLiteralAsExpected.types | 73 +++++++++++++++++++ .../jsxInferenceProducesLiteralAsExpected.tsx | 18 +++++ 5 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.js create mode 100644 tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.symbols create mode 100644 tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.types create mode 100644 tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 121dda33237..80168823b3c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20640,15 +20640,6 @@ namespace ts { return widened; } - function isTypeParameterWithKeyofConstraint(type: Type) { - if (type.flags & TypeFlags.TypeParameter) { - const constraintDeclaration = getConstraintDeclaration(type); - return constraintDeclaration && constraintDeclaration.kind === SyntaxKind.TypeOperator && - (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 diff --git a/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.js b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.js new file mode 100644 index 00000000000..7caee9c06c1 --- /dev/null +++ b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.js @@ -0,0 +1,34 @@ +//// [jsxInferenceProducesLiteralAsExpected.tsx] +import React = require("react"); +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +class TestObject { + a: string = ''; + b: number = 1; + c: () => void = () => { }; +} +interface TestProps { + model: T; + foo: FunctionPropertyNames; +} +function Test(props: TestProps) { return <>; } +const model = new TestObject(); + +const el1 = ; +const el2 = 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" }); diff --git a/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.symbols b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.symbols new file mode 100644 index 00000000000..be05f1dfb66 --- /dev/null +++ b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.symbols @@ -0,0 +1,66 @@ +=== tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx === +import React = require("react"); +>React : Symbol(React, Decl(jsxInferenceProducesLiteralAsExpected.tsx, 0, 0)) + +type FunctionPropertyNames = { [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 { +>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; +>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(props: TestProps) { 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 = ; +>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 = 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)) + diff --git a/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.types b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.types new file mode 100644 index 00000000000..f9b3769d42e --- /dev/null +++ b/tests/baselines/reference/jsxInferenceProducesLiteralAsExpected.types @@ -0,0 +1,73 @@ +=== tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx === +import React = require("react"); +>React : typeof React + +type FunctionPropertyNames = { [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 { +>TestProps : TestProps +>T : T + + model: T; +>model : T +>T : T + + foo: FunctionPropertyNames; +>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(props: TestProps) { return <>; } +>Test : (props: TestProps) => JSX.Element +>T : T +>props : TestProps +>TestProps : TestProps +>T : T +><> : JSX.Element + +const model = new TestObject(); +>model : TestObject +>new TestObject() : TestObject +>TestObject : typeof TestObject + +const el1 = ; +>el1 : JSX.Element +> : JSX.Element +>Test : (props: TestProps) => JSX.Element +>model : TestObject +>model : TestObject +>foo : "c" + +const el2 = model={model} foo="c" />; +>el2 : JSX.Element +> model={model} foo="c" /> : JSX.Element +>Test : (props: TestProps) => JSX.Element +>TestObject : TestObject +>model : TestObject +>model : TestObject +>foo : "c" + diff --git a/tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx b/tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx new file mode 100644 index 00000000000..ce7dc331716 --- /dev/null +++ b/tests/cases/compiler/jsxInferenceProducesLiteralAsExpected.tsx @@ -0,0 +1,18 @@ +// @jsx: react +// @libFiles: lib.d.ts,react.d.ts +import React = require("react"); +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +class TestObject { + a: string = ''; + b: number = 1; + c: () => void = () => { }; +} +interface TestProps { + model: T; + foo: FunctionPropertyNames; +} +function Test(props: TestProps) { return <>; } +const model = new TestObject(); + +const el1 = ; +const el2 = model={model} foo="c" />; \ No newline at end of file