Merge pull request #5596 from RyanCavanaugh/statelessFunctionComponents
Stateless function components in JSX
This commit is contained in:
commit
bc92e4e9b0
11 changed files with 18660 additions and 31 deletions
|
@ -141,9 +141,6 @@ namespace ts {
|
|||
let globalRegExpType: ObjectType;
|
||||
let globalTemplateStringsArrayType: ObjectType;
|
||||
let globalESSymbolType: ObjectType;
|
||||
let jsxElementType: ObjectType;
|
||||
/** Lazily loaded, use getJsxIntrinsicElementType() */
|
||||
let jsxIntrinsicElementsType: ObjectType;
|
||||
let globalIterableType: GenericType;
|
||||
let globalIteratorType: GenericType;
|
||||
let globalIterableIteratorType: GenericType;
|
||||
|
@ -208,12 +205,17 @@ namespace ts {
|
|||
}
|
||||
};
|
||||
|
||||
let jsxElementType: ObjectType;
|
||||
/** Things we lazy load from the JSX namespace */
|
||||
const jsxTypes: Map<ObjectType> = {};
|
||||
const JsxNames = {
|
||||
JSX: "JSX",
|
||||
IntrinsicElements: "IntrinsicElements",
|
||||
ElementClass: "ElementClass",
|
||||
ElementAttributesPropertyNameContainer: "ElementAttributesProperty",
|
||||
Element: "Element"
|
||||
Element: "Element",
|
||||
IntrinsicAttributes: "IntrinsicAttributes",
|
||||
IntrinsicClassAttributes: "IntrinsicClassAttributes"
|
||||
};
|
||||
|
||||
const subtypeRelation: Map<RelationComparisonResult> = {};
|
||||
|
@ -7868,12 +7870,11 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
/// Returns the type JSX.IntrinsicElements. May return `unknownType` if that type is not present.
|
||||
function getJsxIntrinsicElementsType() {
|
||||
if (!jsxIntrinsicElementsType) {
|
||||
jsxIntrinsicElementsType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.IntrinsicElements) || unknownType;
|
||||
function getJsxType(name: string) {
|
||||
if (jsxTypes[name] === undefined) {
|
||||
return jsxTypes[name] = getExportedTypeFromNamespace(JsxNames.JSX, name) || unknownType;
|
||||
}
|
||||
return jsxIntrinsicElementsType;
|
||||
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
|
||||
|
@ -7896,7 +7897,7 @@ namespace ts {
|
|||
return links.resolvedSymbol;
|
||||
|
||||
function lookupIntrinsicTag(node: JsxOpeningLikeElement | JsxClosingElement): Symbol {
|
||||
const intrinsicElementsType = getJsxIntrinsicElementsType();
|
||||
const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements);
|
||||
if (intrinsicElementsType !== unknownType) {
|
||||
// Property case
|
||||
const intrinsicProp = getPropertyOfType(intrinsicElementsType, (<Identifier>node.tagName).text);
|
||||
|
@ -7928,7 +7929,7 @@ namespace ts {
|
|||
|
||||
// Look up the value in the current scope
|
||||
if (valueSymbol && valueSymbol !== unknownSymbol) {
|
||||
links.jsxFlags |= JsxFlags.ClassElement;
|
||||
links.jsxFlags |= JsxFlags.ValueElement;
|
||||
if (valueSymbol.flags & SymbolFlags.Alias) {
|
||||
markAliasSymbolAsReferenced(valueSymbol);
|
||||
}
|
||||
|
@ -7957,7 +7958,7 @@ namespace ts {
|
|||
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.ClassElement), "Should not call getJsxElementInstanceType on non-class Element");
|
||||
Debug.assert(!!(getNodeLinks(node).jsxFlags & JsxFlags.ValueElement), "Should not call getJsxElementInstanceType on non-class Element");
|
||||
|
||||
const classSymbol = getJsxElementTagSymbol(node);
|
||||
if (classSymbol === unknownSymbol) {
|
||||
|
@ -7984,15 +7985,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
const returnType = getUnionType(signatures.map(getReturnTypeOfSignature));
|
||||
|
||||
// Issue an error if this return type isn't assignable to JSX.ElementClass
|
||||
const elemClassType = getJsxGlobalElementClassType();
|
||||
if (elemClassType) {
|
||||
checkTypeRelatedTo(returnType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
|
||||
}
|
||||
|
||||
return returnType;
|
||||
return getUnionType(signatures.map(getReturnTypeOfSignature));
|
||||
}
|
||||
|
||||
/// e.g. "props" for React.d.ts,
|
||||
|
@ -8041,9 +8034,31 @@ namespace ts {
|
|||
if (!links.resolvedJsxType) {
|
||||
const sym = getJsxElementTagSymbol(node);
|
||||
|
||||
if (links.jsxFlags & JsxFlags.ClassElement) {
|
||||
if (links.jsxFlags & JsxFlags.ValueElement) {
|
||||
// Get the element instance type (the result of newing or invoking this tag)
|
||||
const elemInstanceType = getJsxElementInstanceType(node);
|
||||
|
||||
// Is this is a stateless function component? See if its single signature is
|
||||
// assignable to the JSX Element Type
|
||||
const callSignature = getSingleCallSignature(getTypeOfSymbol(sym));
|
||||
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
|
||||
let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
|
||||
if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType) && (paramType.flags & TypeFlags.ObjectType)) {
|
||||
// Intersect in JSX.IntrinsicAttributes if it exists
|
||||
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
|
||||
if (intrinsicAttributes !== unknownType) {
|
||||
paramType = intersectTypes(intrinsicAttributes, paramType);
|
||||
}
|
||||
return paramType;
|
||||
}
|
||||
|
||||
// Issue an error if this return type isn't assignable to JSX.ElementClass
|
||||
const elemClassType = getJsxGlobalElementClassType();
|
||||
if (elemClassType) {
|
||||
checkTypeRelatedTo(elemInstanceType, elemClassType, assignableRelation, node, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
|
||||
}
|
||||
|
||||
|
||||
if (isTypeAny(elemInstanceType)) {
|
||||
return links.resolvedJsxType = elemInstanceType;
|
||||
}
|
||||
|
@ -8065,14 +8080,36 @@ namespace ts {
|
|||
return links.resolvedJsxType = emptyObjectType;
|
||||
}
|
||||
else if (isTypeAny(attributesType) || (attributesType === unknownType)) {
|
||||
// Props is of type 'any' or unknown
|
||||
return links.resolvedJsxType = attributesType;
|
||||
}
|
||||
else if (!(attributesType.flags & TypeFlags.ObjectType)) {
|
||||
// Props is not an object type
|
||||
error(node.tagName, Diagnostics.JSX_element_attributes_type_0_must_be_an_object_type, typeToString(attributesType));
|
||||
return links.resolvedJsxType = anyType;
|
||||
}
|
||||
else {
|
||||
return links.resolvedJsxType = attributesType;
|
||||
// Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
|
||||
let apparentAttributesType = attributesType;
|
||||
const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes);
|
||||
if (intrinsicClassAttribs !== unknownType) {
|
||||
const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
|
||||
if (typeParams) {
|
||||
if (typeParams.length === 1) {
|
||||
apparentAttributesType = intersectTypes(createTypeReference(<GenericType>intrinsicClassAttribs, [elemInstanceType]), apparentAttributesType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
apparentAttributesType = intersectTypes(attributesType, intrinsicClassAttribs);
|
||||
}
|
||||
}
|
||||
|
||||
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes);
|
||||
if (intrinsicAttribs !== unknownType) {
|
||||
apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
|
||||
}
|
||||
|
||||
return links.resolvedJsxType = apparentAttributesType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8111,7 +8148,7 @@ namespace ts {
|
|||
|
||||
/// Returns all the properties of the Jsx.IntrinsicElements interface
|
||||
function getJsxIntrinsicTagNames(): Symbol[] {
|
||||
const intrinsics = getJsxIntrinsicElementsType();
|
||||
const intrinsics = getJsxType(JsxNames.IntrinsicElements);
|
||||
return intrinsics ? getPropertiesOfType(intrinsics) : emptyArray;
|
||||
}
|
||||
|
||||
|
|
|
@ -439,12 +439,16 @@ namespace ts {
|
|||
|
||||
export const enum JsxFlags {
|
||||
None = 0,
|
||||
/** An element from a named property of the JSX.IntrinsicElements interface */
|
||||
IntrinsicNamedElement = 1 << 0,
|
||||
/** An element inferred from the string index signature of the JSX.IntrinsicElements interface */
|
||||
IntrinsicIndexedElement = 1 << 1,
|
||||
ClassElement = 1 << 2,
|
||||
UnknownElement = 1 << 3,
|
||||
/** An element backed by a class, class-like, or function value */
|
||||
ValueElement = 1 << 2,
|
||||
/** Element resolution failed */
|
||||
UnknownElement = 1 << 4,
|
||||
|
||||
IntrinsicElement = IntrinsicNamedElement | IntrinsicIndexedElement
|
||||
IntrinsicElement = IntrinsicNamedElement | IntrinsicIndexedElement,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -908,6 +908,7 @@ namespace Harness {
|
|||
useCaseSensitiveFileNames?: boolean;
|
||||
includeBuiltFile?: string;
|
||||
baselineFile?: string;
|
||||
libFiles?: string;
|
||||
}
|
||||
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
|
@ -917,6 +918,7 @@ namespace Harness {
|
|||
{ name: "baselineFile", type: "string" },
|
||||
{ name: "includeBuiltFile", type: "string" },
|
||||
{ name: "fileName", type: "string" },
|
||||
{ name: "libFiles", type: "string" },
|
||||
{ name: "noErrorTruncation", type: "boolean" }
|
||||
];
|
||||
|
||||
|
@ -995,14 +997,11 @@ namespace Harness {
|
|||
currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory();
|
||||
|
||||
// Parse settings
|
||||
let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames();
|
||||
if (harnessSettings) {
|
||||
setCompilerOptionsFromHarnessSetting(harnessSettings, options);
|
||||
}
|
||||
if (options.useCaseSensitiveFileNames !== undefined) {
|
||||
useCaseSensitiveFileNames = options.useCaseSensitiveFileNames;
|
||||
}
|
||||
|
||||
const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : Harness.IO.useCaseSensitiveFileNames();
|
||||
const programFiles: TestFile[] = inputFiles.slice();
|
||||
// Files from built\local that are requested by test "@includeBuiltFiles" to be in the context.
|
||||
// Treat them as library files, so include them in build, but not in baselines.
|
||||
|
@ -1017,6 +1016,15 @@ namespace Harness {
|
|||
|
||||
const fileOutputs: GeneratedFile[] = [];
|
||||
|
||||
// Files from tests\lib that are requested by "@libFiles"
|
||||
if (options.libFiles) {
|
||||
for (const fileName of options.libFiles.split(",")) {
|
||||
const libFileName = "tests/lib/" + fileName;
|
||||
programFiles.push({ unitName: libFileName, content: normalizeLineEndings(IO.readFile(libFileName), Harness.IO.newLine()) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const programFileNames = programFiles.map(file => file.unitName);
|
||||
|
||||
const compilerHost = createCompilerHost(
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
tests/cases/conformance/jsx/file.tsx(12,9): error TS2324: Property 'name' is missing in type 'IntrinsicAttributes & { name: string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(12,16): error TS2339: Property 'naaame' does not exist on type 'IntrinsicAttributes & { name: string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(19,15): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(21,15): error TS2339: Property 'naaaaaaame' does not exist on type 'IntrinsicAttributes & { name?: string; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (4 errors) ====
|
||||
|
||||
function Greet(x: {name: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
function Meet({name = 'world'}) {
|
||||
return <div>Hello, {name}</div>;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet name='world' />;
|
||||
// Error
|
||||
let b = <Greet naaame='world' />;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2324: Property 'name' is missing in type 'IntrinsicAttributes & { name: string; }'.
|
||||
~~~~~~
|
||||
!!! error TS2339: Property 'naaame' does not exist on type 'IntrinsicAttributes & { name: string; }'.
|
||||
|
||||
// OK
|
||||
let c = <Meet />;
|
||||
// OK
|
||||
let d = <Meet name='me' />;
|
||||
// Error
|
||||
let e = <Meet name={42} />;
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
// Error
|
||||
let f = <Meet naaaaaaame='no' />;
|
||||
~~~~~~~~~~
|
||||
!!! error TS2339: Property 'naaaaaaame' does not exist on type 'IntrinsicAttributes & { name?: string; }'.
|
||||
|
44
tests/baselines/reference/tsxStatelessFunctionComponents1.js
Normal file
44
tests/baselines/reference/tsxStatelessFunctionComponents1.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
//// [file.tsx]
|
||||
|
||||
function Greet(x: {name: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
function Meet({name = 'world'}) {
|
||||
return <div>Hello, {name}</div>;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet name='world' />;
|
||||
// Error
|
||||
let b = <Greet naaame='world' />;
|
||||
|
||||
// OK
|
||||
let c = <Meet />;
|
||||
// OK
|
||||
let d = <Meet name='me' />;
|
||||
// Error
|
||||
let e = <Meet name={42} />;
|
||||
// Error
|
||||
let f = <Meet naaaaaaame='no' />;
|
||||
|
||||
|
||||
//// [file.jsx]
|
||||
function Greet(x) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
function Meet(_a) {
|
||||
var _b = _a.name, name = _b === void 0 ? 'world' : _b;
|
||||
return <div>Hello, {name}</div>;
|
||||
}
|
||||
// OK
|
||||
var a = <Greet name='world'/>;
|
||||
// Error
|
||||
var b = <Greet naaame='world'/>;
|
||||
// OK
|
||||
var c = <Meet />;
|
||||
// OK
|
||||
var d = <Meet name='me'/>;
|
||||
// Error
|
||||
var e = <Meet name={42}/>;
|
||||
// Error
|
||||
var f = <Meet naaaaaaame='no'/>;
|
|
@ -0,0 +1,56 @@
|
|||
tests/cases/conformance/jsx/file.tsx(2,1): error TS1148: Cannot compile modules unless the '--module' flag is provided.
|
||||
tests/cases/conformance/jsx/file.tsx(20,16): error TS2339: Property 'ref' does not exist on type 'IntrinsicAttributes & { name?: string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(26,42): error TS2339: Property 'subtr' does not exist on type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(28,33): error TS2339: Property 'notARealProperty' does not exist on type 'BigGreeter'.
|
||||
tests/cases/conformance/jsx/file.tsx(36,26): error TS2339: Property 'propertyNotOnHtmlDivElement' does not exist on type 'HTMLDivElement'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (5 errors) ====
|
||||
|
||||
import React = require('react');
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1148: Cannot compile modules unless the '--module' flag is provided.
|
||||
|
||||
function Greet(x: {name?: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
|
||||
class BigGreeter extends React.Component<{ name?: string }, {}> {
|
||||
render() {
|
||||
return <div></div>;
|
||||
}
|
||||
greeting: string;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet />;
|
||||
// OK - always valid to specify 'key'
|
||||
let b = <Greet key="k" />;
|
||||
// Error - not allowed to specify 'ref' on SFCs
|
||||
let c = <Greet ref="myRef" />;
|
||||
~~~
|
||||
!!! error TS2339: Property 'ref' does not exist on type 'IntrinsicAttributes & { name?: string; }'.
|
||||
|
||||
|
||||
// OK - ref is valid for classes
|
||||
let d = <BigGreeter ref={x => x.greeting.substr(10)} />;
|
||||
// Error ('subtr' not on string)
|
||||
let e = <BigGreeter ref={x => x.greeting.subtr(10)} />;
|
||||
~~~~~
|
||||
!!! error TS2339: Property 'subtr' does not exist on type 'string'.
|
||||
// Error (ref callback is contextually typed)
|
||||
let f = <BigGreeter ref={x => x.notARealProperty} />;
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'notARealProperty' does not exist on type 'BigGreeter'.
|
||||
|
||||
// OK - key is always valid
|
||||
let g = <BigGreeter key={100} />;
|
||||
|
||||
// OK - contextually typed intrinsic ref callback parameter
|
||||
let h = <div ref={x => x.innerText} />;
|
||||
// Error - property not on ontextually typed intrinsic ref callback parameter
|
||||
let i = <div ref={x => x.propertyNotOnHtmlDivElement} />;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'propertyNotOnHtmlDivElement' does not exist on type 'HTMLDivElement'.
|
||||
|
||||
|
79
tests/baselines/reference/tsxStatelessFunctionComponents2.js
Normal file
79
tests/baselines/reference/tsxStatelessFunctionComponents2.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
//// [file.tsx]
|
||||
|
||||
import React = require('react');
|
||||
|
||||
function Greet(x: {name?: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
|
||||
class BigGreeter extends React.Component<{ name?: string }, {}> {
|
||||
render() {
|
||||
return <div></div>;
|
||||
}
|
||||
greeting: string;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet />;
|
||||
// OK - always valid to specify 'key'
|
||||
let b = <Greet key="k" />;
|
||||
// Error - not allowed to specify 'ref' on SFCs
|
||||
let c = <Greet ref="myRef" />;
|
||||
|
||||
|
||||
// OK - ref is valid for classes
|
||||
let d = <BigGreeter ref={x => x.greeting.substr(10)} />;
|
||||
// Error ('subtr' not on string)
|
||||
let e = <BigGreeter ref={x => x.greeting.subtr(10)} />;
|
||||
// Error (ref callback is contextually typed)
|
||||
let f = <BigGreeter ref={x => x.notARealProperty} />;
|
||||
|
||||
// OK - key is always valid
|
||||
let g = <BigGreeter key={100} />;
|
||||
|
||||
// OK - contextually typed intrinsic ref callback parameter
|
||||
let h = <div ref={x => x.innerText} />;
|
||||
// Error - property not on ontextually typed intrinsic ref callback parameter
|
||||
let i = <div ref={x => x.propertyNotOnHtmlDivElement} />;
|
||||
|
||||
|
||||
|
||||
//// [file.jsx]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var React = require('react');
|
||||
function Greet(x) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
var BigGreeter = (function (_super) {
|
||||
__extends(BigGreeter, _super);
|
||||
function BigGreeter() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
BigGreeter.prototype.render = function () {
|
||||
return <div></div>;
|
||||
};
|
||||
return BigGreeter;
|
||||
})(React.Component);
|
||||
// OK
|
||||
var a = <Greet />;
|
||||
// OK - always valid to specify 'key'
|
||||
var b = <Greet key="k"/>;
|
||||
// Error - not allowed to specify 'ref' on SFCs
|
||||
var c = <Greet ref="myRef"/>;
|
||||
// OK - ref is valid for classes
|
||||
var d = <BigGreeter ref={function (x) { return x.greeting.substr(10); }}/>;
|
||||
// Error ('subtr' not on string)
|
||||
var e = <BigGreeter ref={function (x) { return x.greeting.subtr(10); }}/>;
|
||||
// Error (ref callback is contextually typed)
|
||||
var f = <BigGreeter ref={function (x) { return x.notARealProperty; }}/>;
|
||||
// OK - key is always valid
|
||||
var g = <BigGreeter key={100}/>;
|
||||
// OK - contextually typed intrinsic ref callback parameter
|
||||
var h = <div ref={function (x) { return x.innerText; }}/>;
|
||||
// Error - property not on ontextually typed intrinsic ref callback parameter
|
||||
var i = <div ref={function (x) { return x.propertyNotOnHtmlDivElement; }}/>;
|
|
@ -0,0 +1,25 @@
|
|||
// @filename: file.tsx
|
||||
// @jsx: preserve
|
||||
// @noLib: true
|
||||
// @libFiles: react.d.ts,lib.d.ts
|
||||
|
||||
function Greet(x: {name: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
function Meet({name = 'world'}) {
|
||||
return <div>Hello, {name}</div>;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet name='world' />;
|
||||
// Error
|
||||
let b = <Greet naaame='world' />;
|
||||
|
||||
// OK
|
||||
let c = <Meet />;
|
||||
// OK
|
||||
let d = <Meet name='me' />;
|
||||
// Error
|
||||
let e = <Meet name={42} />;
|
||||
// Error
|
||||
let f = <Meet naaaaaaame='no' />;
|
|
@ -0,0 +1,41 @@
|
|||
// @filename: file.tsx
|
||||
// @jsx: preserve
|
||||
// @noLib: true
|
||||
// @libFiles: react.d.ts,lib.d.ts
|
||||
|
||||
import React = require('react');
|
||||
|
||||
function Greet(x: {name?: string}) {
|
||||
return <div>Hello, {x}</div>;
|
||||
}
|
||||
|
||||
class BigGreeter extends React.Component<{ name?: string }, {}> {
|
||||
render() {
|
||||
return <div></div>;
|
||||
}
|
||||
greeting: string;
|
||||
}
|
||||
|
||||
// OK
|
||||
let a = <Greet />;
|
||||
// OK - always valid to specify 'key'
|
||||
let b = <Greet key="k" />;
|
||||
// Error - not allowed to specify 'ref' on SFCs
|
||||
let c = <Greet ref="myRef" />;
|
||||
|
||||
|
||||
// OK - ref is valid for classes
|
||||
let d = <BigGreeter ref={x => x.greeting.substr(10)} />;
|
||||
// Error ('subtr' not on string)
|
||||
let e = <BigGreeter ref={x => x.greeting.subtr(10)} />;
|
||||
// Error (ref callback is contextually typed)
|
||||
let f = <BigGreeter ref={x => x.notARealProperty} />;
|
||||
|
||||
// OK - key is always valid
|
||||
let g = <BigGreeter key={100} />;
|
||||
|
||||
// OK - contextually typed intrinsic ref callback parameter
|
||||
let h = <div ref={x => x.innerText} />;
|
||||
// Error - property not on ontextually typed intrinsic ref callback parameter
|
||||
let i = <div ref={x => x.propertyNotOnHtmlDivElement} />;
|
||||
|
17264
tests/lib/lib.d.ts
vendored
Normal file
17264
tests/lib/lib.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
1034
tests/lib/react.d.ts
vendored
Normal file
1034
tests/lib/react.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue