mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 11:24:49 -05:00
@@ -8365,7 +8365,7 @@ namespace ts {
|
||||
checkJsxOpeningLikeElement(node.openingElement);
|
||||
|
||||
// Perform resolution on the closing tag so that rename/go to definition/etc work
|
||||
getJsxElementTagSymbol(node.closingElement);
|
||||
getJsxTagSymbol(node.closingElement);
|
||||
|
||||
// Check children
|
||||
for (const child of node.children) {
|
||||
@@ -8475,77 +8475,53 @@ namespace ts {
|
||||
return jsxTypes[name];
|
||||
}
|
||||
|
||||
/// Given a JSX opening element or self-closing element, return the symbol of the property that the tag name points to if
|
||||
/// this is an intrinsic tag. This might be a named
|
||||
/// property of the IntrinsicElements interface, or its string indexer.
|
||||
/// If this is a class-based tag (otherwise returns undefined), returns the symbol of the class
|
||||
/// type or factory function.
|
||||
/// Otherwise, returns unknownSymbol.
|
||||
function getJsxElementTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
function getJsxTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
const links = getNodeLinks(node);
|
||||
if (isJsxIntrinsicIdentifier(node.tagName)) {
|
||||
return getIntrinsicTagSymbol(node);
|
||||
}
|
||||
else {
|
||||
return resolveEntityName(node.tagName, SymbolFlags.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an intrinsic tag name and returns a symbol that either points to an intrinsic
|
||||
* property (in which case nodeLinks.jsxFlags will be IntrinsicNamedElement) or an intrinsic
|
||||
* string index signature (in which case nodeLinks.jsxFlags will be IntrinsicIndexedElement).
|
||||
* May also return unknownSymbol if both of these lookups fail.
|
||||
*/
|
||||
function getIntrinsicTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedSymbol) {
|
||||
if (isJsxIntrinsicIdentifier(node.tagName)) {
|
||||
links.resolvedSymbol = lookupIntrinsicTag(node);
|
||||
}
|
||||
else {
|
||||
links.resolvedSymbol = lookupClassTag(node);
|
||||
}
|
||||
}
|
||||
return links.resolvedSymbol;
|
||||
|
||||
function lookupIntrinsicTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements);
|
||||
if (intrinsicElementsType !== unknownType) {
|
||||
// Property case
|
||||
const intrinsicProp = getPropertyOfType(intrinsicElementsType, (<Identifier>node.tagName).text);
|
||||
if (intrinsicProp) {
|
||||
links.jsxFlags |= JsxFlags.IntrinsicNamedElement;
|
||||
return intrinsicProp;
|
||||
return links.resolvedSymbol = intrinsicProp;
|
||||
}
|
||||
|
||||
// Intrinsic string indexer case
|
||||
const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, IndexKind.String);
|
||||
if (indexSignatureType) {
|
||||
links.jsxFlags |= JsxFlags.IntrinsicIndexedElement;
|
||||
return intrinsicElementsType.symbol;
|
||||
return links.resolvedSymbol = intrinsicElementsType.symbol;
|
||||
}
|
||||
|
||||
// Wasn't found
|
||||
error(node, Diagnostics.Property_0_does_not_exist_on_type_1, (<Identifier>node.tagName).text, "JSX." + JsxNames.IntrinsicElements);
|
||||
return unknownSymbol;
|
||||
return links.resolvedSymbol = unknownSymbol;
|
||||
}
|
||||
else {
|
||||
if (compilerOptions.noImplicitAny) {
|
||||
error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, JsxNames.IntrinsicElements);
|
||||
}
|
||||
return unknownSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
function lookupClassTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
const valueSymbol: Symbol = resolveJsxTagName(node);
|
||||
|
||||
// Look up the value in the current scope
|
||||
if (valueSymbol && valueSymbol !== unknownSymbol) {
|
||||
links.jsxFlags |= JsxFlags.ValueElement;
|
||||
if (valueSymbol.flags & SymbolFlags.Alias) {
|
||||
markAliasSymbolAsReferenced(valueSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
return valueSymbol || unknownSymbol;
|
||||
}
|
||||
|
||||
function resolveJsxTagName(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
if (node.tagName.kind === SyntaxKind.Identifier) {
|
||||
const tag = <Identifier>node.tagName;
|
||||
const sym = getResolvedSymbol(tag);
|
||||
return sym.exportSymbol || sym;
|
||||
}
|
||||
else {
|
||||
return checkQualifiedName(<QualifiedName>node.tagName).symbol;
|
||||
return links.resolvedSymbol = unknownSymbol;
|
||||
}
|
||||
}
|
||||
return links.resolvedSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8554,17 +8530,8 @@ namespace ts {
|
||||
* For example, in the element <MyClass>, the element instance type is `MyClass` (not `typeof MyClass`).
|
||||
*/
|
||||
function getJsxElementInstanceType(node: JsxOpeningLikeElement) {
|
||||
// There is no such thing as an instance type for a non-class element. This
|
||||
// line shouldn't be hit.
|
||||
Debug.assert(!!(getNodeLinks(node).jsxFlags & JsxFlags.ValueElement), "Should not call getJsxElementInstanceType on non-class Element");
|
||||
const valueType = checkExpression(node.tagName);
|
||||
|
||||
const classSymbol = getJsxElementTagSymbol(node);
|
||||
if (classSymbol === unknownSymbol) {
|
||||
// Couldn't find the class instance type. Error has already been issued
|
||||
return anyType;
|
||||
}
|
||||
|
||||
const valueType = getTypeOfSymbol(classSymbol);
|
||||
if (isTypeAny(valueType)) {
|
||||
// Short-circuit if the class tag is using an element type 'any'
|
||||
return anyType;
|
||||
@@ -8630,9 +8597,16 @@ namespace ts {
|
||||
function getJsxElementAttributesType(node: JsxOpeningLikeElement): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedJsxType) {
|
||||
const sym = getJsxElementTagSymbol(node);
|
||||
|
||||
if (links.jsxFlags & JsxFlags.ValueElement) {
|
||||
if (isJsxIntrinsicIdentifier(node.tagName)) {
|
||||
const symbol = getIntrinsicTagSymbol(node);
|
||||
if (links.jsxFlags & JsxFlags.IntrinsicNamedElement) {
|
||||
return links.resolvedJsxType = getTypeOfSymbol(symbol);
|
||||
}
|
||||
else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) {
|
||||
return links.resolvedJsxType = getIndexInfoOfSymbol(symbol, IndexKind.String).type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Get the element instance type (the result of newing or invoking this tag)
|
||||
const elemInstanceType = getJsxElementInstanceType(node);
|
||||
|
||||
@@ -8641,7 +8615,7 @@ namespace ts {
|
||||
if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) {
|
||||
// Is this is a stateless function component? See if its single signature's return type is
|
||||
// assignable to the JSX Element Type
|
||||
const elemType = getTypeOfSymbol(sym);
|
||||
const elemType = checkExpression(node.tagName);
|
||||
const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
|
||||
const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
|
||||
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
|
||||
@@ -8715,16 +8689,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (links.jsxFlags & JsxFlags.IntrinsicNamedElement) {
|
||||
return links.resolvedJsxType = getTypeOfSymbol(sym);
|
||||
}
|
||||
else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) {
|
||||
return links.resolvedJsxType = getIndexInfoOfSymbol(sym, IndexKind.String).type;
|
||||
}
|
||||
else {
|
||||
// Resolution failed, so we don't know
|
||||
return links.resolvedJsxType = anyType;
|
||||
}
|
||||
|
||||
return links.resolvedJsxType = unknownType;
|
||||
}
|
||||
|
||||
return links.resolvedJsxType;
|
||||
@@ -15431,7 +15397,8 @@ namespace ts {
|
||||
else if ((entityName.parent.kind === SyntaxKind.JsxOpeningElement) ||
|
||||
(entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) ||
|
||||
(entityName.parent.kind === SyntaxKind.JsxClosingElement)) {
|
||||
return getJsxElementTagSymbol(<JsxOpeningLikeElement>entityName.parent);
|
||||
|
||||
return getJsxTagSymbol(<JsxOpeningLikeElement>entityName.parent);
|
||||
}
|
||||
else if (isExpression(entityName)) {
|
||||
if (nodeIsMissing(entityName)) {
|
||||
|
||||
@@ -422,10 +422,6 @@ namespace ts {
|
||||
IntrinsicNamedElement = 1 << 0,
|
||||
/** An element inferred from the string index signature of the JSX.IntrinsicElements interface */
|
||||
IntrinsicIndexedElement = 1 << 1,
|
||||
/** An element backed by a class, class-like, or function value */
|
||||
ValueElement = 1 << 2,
|
||||
/** Element resolution failed */
|
||||
UnknownElement = 1 << 4,
|
||||
|
||||
IntrinsicElement = IntrinsicNamedElement | IntrinsicIndexedElement,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,29): error TS1005: '{'
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,57): error TS1109: Expression expected.
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(39,58): error TS1109: Expression expected.
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(41,1): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(41,8): error TS2503: Cannot find namespace 'a'.
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(41,12): error TS2657: JSX expressions must have one parent element
|
||||
tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(43,10): error TS2503: Cannot find namespace 'a'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx (7 errors) ====
|
||||
==== tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx (9 errors) ====
|
||||
declare var React: any;
|
||||
declare var 日本語;
|
||||
declare var AbC_def;
|
||||
@@ -61,10 +63,14 @@ tests/cases/conformance/jsx/jsxEsprimaFbTestSuite.tsx(41,12): error TS2657: JSX
|
||||
<a.b></a.b>;
|
||||
~
|
||||
!!! error TS1003: Identifier expected.
|
||||
~
|
||||
!!! error TS2503: Cannot find namespace 'a'.
|
||||
~
|
||||
!!! error TS2657: JSX expressions must have one parent element
|
||||
|
||||
<a.b.c></a.b.c>;
|
||||
~
|
||||
!!! error TS2503: Cannot find namespace 'a'.
|
||||
|
||||
(<div />) < x;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(11,12): error TS2304:
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(11,16): error TS1109: Expression expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,2): error TS2304: Cannot find name 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,5): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,10): error TS2304: Cannot find name 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,10): error TS2503: Cannot find namespace 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,13): error TS1005: '>' expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,14): error TS2304: Cannot find name 'c'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(12,16): error TS1109: Expression expected.
|
||||
@@ -38,7 +38,7 @@ tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(14,8): error TS2304:
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(14,10): error TS1109: Expression expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,2): error TS2304: Cannot find name 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,4): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,7): error TS2304: Cannot find name 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,7): error TS2503: Cannot find namespace 'a'.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(15,9): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(16,3): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(16,4): error TS2304: Cannot find name 'foo'.
|
||||
@@ -135,7 +135,7 @@ tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(35,21): error TS1005:
|
||||
~
|
||||
!!! error TS1003: Identifier expected.
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'a'.
|
||||
!!! error TS2503: Cannot find namespace 'a'.
|
||||
~
|
||||
!!! error TS1005: '>' expected.
|
||||
~
|
||||
@@ -166,7 +166,7 @@ tests/cases/conformance/jsx/jsxInvalidEsprimaTestSuite.tsx(35,21): error TS1005:
|
||||
~
|
||||
!!! error TS1003: Identifier expected.
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'a'.
|
||||
!!! error TS2503: Cannot find namespace 'a'.
|
||||
~
|
||||
!!! error TS1003: Identifier expected.
|
||||
<a[foo]></a[foo]>;
|
||||
|
||||
@@ -178,10 +178,8 @@ var x =
|
||||
>constructor : Symbol(unknown)
|
||||
|
||||
<Namespace.Component />;
|
||||
>Component : Symbol(unknown)
|
||||
|
||||
<Namespace.DeepNamespace.Component />;
|
||||
>Component : Symbol(unknown)
|
||||
|
||||
<Component { ... x } y
|
||||
>Component : Symbol(Component, Decl(jsxReactTestSuite.tsx, 2, 11))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
tests/cases/conformance/jsx/file.tsx(26,10): error TS2324: Property 'reqd' is missing in type 'IntrinsicAttributes & { reqd: any; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(29,10): error TS2324: Property 'reqd' is missing in type 'IntrinsicAttributes & { reqd: any; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/react.d.ts (0 errors) ====
|
||||
@@ -15,7 +16,7 @@ tests/cases/conformance/jsx/file.tsx(26,10): error TS2324: Property 'reqd' is mi
|
||||
}
|
||||
}
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
|
||||
|
||||
declare class Component<P, S> {
|
||||
constructor(props?: P, context?: any);
|
||||
@@ -47,5 +48,7 @@ tests/cases/conformance/jsx/file.tsx(26,10): error TS2324: Property 'reqd' is mi
|
||||
|
||||
// Should error
|
||||
var t2 = <TestMod.Test />;
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2324: Property 'reqd' is missing in type 'IntrinsicAttributes & { reqd: any; }'.
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
=== tests/cases/conformance/jsx/react.d.ts ===
|
||||
|
||||
declare module JSX {
|
||||
>JSX : Symbol(JSX, Decl(react.d.ts, 0, 0))
|
||||
|
||||
interface Element { }
|
||||
>Element : Symbol(Element, Decl(react.d.ts, 1, 20))
|
||||
|
||||
interface IntrinsicElements {
|
||||
>IntrinsicElements : Symbol(IntrinsicElements, Decl(react.d.ts, 2, 22))
|
||||
}
|
||||
interface ElementAttributesProperty {
|
||||
>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(react.d.ts, 4, 2))
|
||||
|
||||
props;
|
||||
>props : Symbol(props, Decl(react.d.ts, 5, 38))
|
||||
}
|
||||
interface IntrinsicAttributes {
|
||||
>IntrinsicAttributes : Symbol(IntrinsicAttributes, Decl(react.d.ts, 7, 2))
|
||||
|
||||
ref?: string;
|
||||
>ref : Symbol(ref, Decl(react.d.ts, 8, 32))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
declare module TestMod {
|
||||
>TestMod : Symbol(TestMod, Decl(file.tsx, 0, 0))
|
||||
|
||||
interface TestClass {
|
||||
>TestClass : Symbol(TestClass, Decl(file.tsx, 0, 24))
|
||||
|
||||
props: { reqd: any };
|
||||
>props : Symbol(props, Decl(file.tsx, 1, 22))
|
||||
>reqd : Symbol(reqd, Decl(file.tsx, 2, 10))
|
||||
}
|
||||
var Test: TestClass;
|
||||
>Test : Symbol(Test, Decl(file.tsx, 4, 4))
|
||||
>TestClass : Symbol(TestClass, Decl(file.tsx, 0, 24))
|
||||
}
|
||||
|
||||
// Should error
|
||||
var test = <TestMod.Test />
|
||||
>test : Symbol(test, Decl(file.tsx, 8, 3))
|
||||
>Test : Symbol(TestMod.TestClass, Decl(file.tsx, 0, 24))
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
=== tests/cases/conformance/jsx/react.d.ts ===
|
||||
|
||||
declare module JSX {
|
||||
>JSX : any
|
||||
|
||||
interface Element { }
|
||||
>Element : Element
|
||||
|
||||
interface IntrinsicElements {
|
||||
>IntrinsicElements : IntrinsicElements
|
||||
}
|
||||
interface ElementAttributesProperty {
|
||||
>ElementAttributesProperty : ElementAttributesProperty
|
||||
|
||||
props;
|
||||
>props : any
|
||||
}
|
||||
interface IntrinsicAttributes {
|
||||
>IntrinsicAttributes : IntrinsicAttributes
|
||||
|
||||
ref?: string;
|
||||
>ref : string
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
declare module TestMod {
|
||||
>TestMod : typeof TestMod
|
||||
|
||||
interface TestClass {
|
||||
>TestClass : TestClass
|
||||
|
||||
props: { reqd: any };
|
||||
>props : { reqd: any; }
|
||||
>reqd : any
|
||||
}
|
||||
var Test: TestClass;
|
||||
>Test : TestClass
|
||||
>TestClass : TestClass
|
||||
}
|
||||
|
||||
// Should error
|
||||
var test = <TestMod.Test />
|
||||
>test : JSX.Element
|
||||
><TestMod.Test /> : JSX.Element
|
||||
>TestMod : any
|
||||
>Test : any
|
||||
|
||||
|
||||
@@ -24,5 +24,5 @@ import {MyClass} from './file1';
|
||||
>MyClass : Symbol(MyClass, Decl(file2.tsx, 3, 8))
|
||||
|
||||
<MyClass />;
|
||||
>MyClass : Symbol(MyClass, Decl(file2.tsx, 3, 8))
|
||||
>MyClass : Symbol(MyClass, Decl(file1.tsx, 2, 1))
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export class App extends React.Component<any, any> {
|
||||
>render : Symbol(render, Decl(app.tsx, 5, 52))
|
||||
|
||||
return <Button />;
|
||||
>Button : Symbol(Button, Decl(app.tsx, 3, 8))
|
||||
>Button : Symbol(Button, Decl(button.tsx, 0, 31))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@ declare module A.B.C {
|
||||
}
|
||||
|
||||
<A.B.C.D>foo</A . B . C.D>
|
||||
>D : Symbol(unknown)
|
||||
>D : Symbol(unknown)
|
||||
>D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5))
|
||||
>D : Symbol(A.B.C.D, Decl(file.tsx, 5, 5))
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import Route = ReactRouter.Route;
|
||||
|
||||
var routes1 = <Route />;
|
||||
>routes1 : Symbol(routes1, Decl(test.tsx, 6, 3))
|
||||
>Route : Symbol(Route, Decl(test.tsx, 2, 45))
|
||||
>Route : Symbol(ReactRouter.Route, Decl(react.d.ts, 7, 4))
|
||||
|
||||
module M {
|
||||
>M : Symbol(M, Decl(test.tsx, 6, 24), Decl(test.tsx, 10, 1))
|
||||
|
||||
Reference in New Issue
Block a user