Merge pull request #6232 from Microsoft/contextuallyTypeJsxStringLiteralAttributes
Contextually type JSX string literal attributes
This commit is contained in:
commit
2cb7ab9692
4 changed files with 87 additions and 14 deletions
|
@ -7474,24 +7474,22 @@ namespace ts {
|
||||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
|
function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) {
|
||||||
// Contextual type only applies to JSX expressions that are in attribute assignments (not in 'Children' positions)
|
const kind = attribute.kind;
|
||||||
if (expr.parent.kind === SyntaxKind.JsxAttribute) {
|
const jsxElement = attribute.parent as JsxOpeningLikeElement;
|
||||||
const attrib = <JsxAttribute>expr.parent;
|
const attrsType = getJsxElementAttributesType(jsxElement);
|
||||||
const attrsType = getJsxElementAttributesType(<JsxOpeningLikeElement>attrib.parent);
|
|
||||||
|
if (attribute.kind === SyntaxKind.JsxAttribute) {
|
||||||
if (!attrsType || isTypeAny(attrsType)) {
|
if (!attrsType || isTypeAny(attrsType)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
else {
|
return getTypeOfPropertyOfType(attrsType, (attribute as JsxAttribute).name.text);
|
||||||
return getTypeOfPropertyOfType(attrsType, attrib.name.text);
|
}
|
||||||
}
|
else if (attribute.kind === SyntaxKind.JsxSpreadAttribute) {
|
||||||
|
return attrsType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr.kind === SyntaxKind.JsxSpreadAttribute) {
|
Debug.fail(`Expected JsxAttribute or JsxSpreadAttribute, got ts.SyntaxKind[${kind}]`);
|
||||||
return getJsxElementAttributesType(<JsxOpeningLikeElement>expr.parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
||||||
|
@ -7559,8 +7557,10 @@ namespace ts {
|
||||||
case SyntaxKind.ParenthesizedExpression:
|
case SyntaxKind.ParenthesizedExpression:
|
||||||
return getContextualType(<ParenthesizedExpression>parent);
|
return getContextualType(<ParenthesizedExpression>parent);
|
||||||
case SyntaxKind.JsxExpression:
|
case SyntaxKind.JsxExpression:
|
||||||
|
return getContextualType(<JsxExpression>parent);
|
||||||
|
case SyntaxKind.JsxAttribute:
|
||||||
case SyntaxKind.JsxSpreadAttribute:
|
case SyntaxKind.JsxSpreadAttribute:
|
||||||
return getContextualTypeForJsxExpression(<JsxExpression>parent);
|
return getContextualTypeForJsxAttribute(<JsxAttribute | JsxSpreadAttribute>parent);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(13,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
|
||||||
|
Type '"f"' is not assignable to type '"C"'.
|
||||||
|
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(14,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
|
||||||
|
Type '"f"' is not assignable to type '"C"'.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx (2 errors) ====
|
||||||
|
|
||||||
|
namespace JSX {
|
||||||
|
interface IntrinsicElements {
|
||||||
|
span: {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;
|
||||||
|
|
||||||
|
<FooComponent foo={"A"} />;
|
||||||
|
<FooComponent foo="A" />;
|
||||||
|
|
||||||
|
<FooComponent foo={"f"} />;
|
||||||
|
~~~~~~~~~
|
||||||
|
!!! error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
|
||||||
|
!!! error TS2322: Type '"f"' is not assignable to type '"C"'.
|
||||||
|
<FooComponent foo="f" />;
|
||||||
|
~~~~~~~
|
||||||
|
!!! error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
|
||||||
|
!!! error TS2322: Type '"f"' is not assignable to type '"C"'.
|
|
@ -0,0 +1,30 @@
|
||||||
|
//// [contextuallyTypedStringLiteralsInJsxAttributes01.tsx]
|
||||||
|
|
||||||
|
namespace JSX {
|
||||||
|
interface IntrinsicElements {
|
||||||
|
span: {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;
|
||||||
|
|
||||||
|
<FooComponent foo={"A"} />;
|
||||||
|
<FooComponent foo="A" />;
|
||||||
|
|
||||||
|
<FooComponent foo={"f"} />;
|
||||||
|
<FooComponent foo="f" />;
|
||||||
|
|
||||||
|
//// [contextuallyTypedStringLiteralsInJsxAttributes01.jsx]
|
||||||
|
var FooComponent = function (props) { return <span>{props.foo}</span>; };
|
||||||
|
<FooComponent foo={"A"}/>;
|
||||||
|
<FooComponent foo="A"/>;
|
||||||
|
<FooComponent foo={"f"}/>;
|
||||||
|
<FooComponent foo="f"/>;
|
||||||
|
|
||||||
|
|
||||||
|
//// [contextuallyTypedStringLiteralsInJsxAttributes01.d.ts]
|
||||||
|
declare namespace JSX {
|
||||||
|
}
|
||||||
|
declare const FooComponent: (props: {
|
||||||
|
foo: "A" | "B" | "C";
|
||||||
|
}) => any;
|
|
@ -0,0 +1,16 @@
|
||||||
|
// @jsx: preserve
|
||||||
|
// @declaration: true
|
||||||
|
|
||||||
|
namespace JSX {
|
||||||
|
interface IntrinsicElements {
|
||||||
|
span: {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;
|
||||||
|
|
||||||
|
<FooComponent foo={"A"} />;
|
||||||
|
<FooComponent foo="A" />;
|
||||||
|
|
||||||
|
<FooComponent foo={"f"} />;
|
||||||
|
<FooComponent foo="f" />;
|
Loading…
Reference in a new issue