mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Do not rely on ElementAttributeProperty if it is not present (#22936)
* Do not rely on ElementAttributeProperty if it is not present * Fix bug * Fix nits and lint
This commit is contained in:
+75
-87
@@ -14766,11 +14766,11 @@ namespace ts {
|
||||
signatures = mapDefined(signatures, s => getJsxSignatureTypeArgumentInstantiation(s, context, isJs));
|
||||
}
|
||||
|
||||
return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromConstructSignature(t, isJs, context) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
|
||||
return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromClassType(t, isJs, context, /*reportErrors*/ false) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None);
|
||||
}
|
||||
|
||||
function getJsxPropsTypeFromCallSignature(sig: Signature, context: Node) {
|
||||
let propsType = getTypeOfFirstParameterOfSignature(sig);
|
||||
let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, emptyObjectType);
|
||||
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context);
|
||||
if (intrinsicAttribs !== unknownType) {
|
||||
propsType = intersectTypes(intrinsicAttribs, propsType);
|
||||
@@ -14778,68 +14778,57 @@ namespace ts {
|
||||
return propsType;
|
||||
}
|
||||
|
||||
function getJsxPropsTypeFromClassType(hostClassType: Type, isJs: boolean, context: JsxOpeningLikeElement, reportErrors: boolean) {
|
||||
if (isTypeAny(hostClassType)) {
|
||||
return hostClassType;
|
||||
}
|
||||
function getJsxPropsTypeForSignatureFromMember(sig: Signature, forcedLookupLocation: __String) {
|
||||
const instanceType = getReturnTypeOfSignature(sig);
|
||||
return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation);
|
||||
}
|
||||
|
||||
const propsName = getJsxElementPropertiesName(getJsxNamespaceAt(context));
|
||||
if (propsName === undefined) {
|
||||
// There is no type ElementAttributesProperty, return 'any'
|
||||
return anyType;
|
||||
function getJsxPropsTypeFromClassType(sig: Signature, isJs: boolean, context: JsxOpeningLikeElement, reportErrors: boolean) {
|
||||
const forcedLookupLocation = getJsxElementPropertiesName(getJsxNamespaceAt(context));
|
||||
const attributesType = forcedLookupLocation === undefined
|
||||
// If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type
|
||||
? getTypeOfFirstParameterOfSignatureWithFallback(sig, emptyObjectType)
|
||||
: forcedLookupLocation === ""
|
||||
// If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
|
||||
? getReturnTypeOfSignature(sig)
|
||||
// Otherwise get the type of the property on the signature return type
|
||||
: getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation);
|
||||
|
||||
if (!attributesType) {
|
||||
// There is no property named 'props' on this instance type
|
||||
if (reportErrors && !!forcedLookupLocation && !!length(context.attributes.properties)) {
|
||||
error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation));
|
||||
}
|
||||
return emptyObjectType;
|
||||
}
|
||||
else if (propsName === "") {
|
||||
// If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
|
||||
return hostClassType;
|
||||
else if (isTypeAny(attributesType)) {
|
||||
// Props is of type 'any' or unknown
|
||||
return attributesType;
|
||||
}
|
||||
else {
|
||||
const attributesType = getTypeOfPropertyOfType(hostClassType, propsName);
|
||||
|
||||
if (!attributesType) {
|
||||
// There is no property named 'props' on this instance type
|
||||
if (reportErrors && !!length(context.attributes.properties)) {
|
||||
error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(propsName));
|
||||
}
|
||||
return emptyObjectType;
|
||||
// Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
|
||||
let apparentAttributesType = attributesType;
|
||||
const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context);
|
||||
if (intrinsicClassAttribs !== unknownType) {
|
||||
const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
|
||||
const hostClassType = getReturnTypeOfSignature(sig);
|
||||
apparentAttributesType = intersectTypes(
|
||||
typeParams
|
||||
? createTypeReference(<GenericType>intrinsicClassAttribs, fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isJs))
|
||||
: intrinsicClassAttribs,
|
||||
apparentAttributesType
|
||||
);
|
||||
}
|
||||
else if (isTypeAny(attributesType)) {
|
||||
// Props is of type 'any' or unknown
|
||||
return attributesType;
|
||||
}
|
||||
else {
|
||||
// Normal case -- add in IntrinsicClassElements<T> and IntrinsicElements
|
||||
let apparentAttributesType = attributesType;
|
||||
const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context);
|
||||
if (intrinsicClassAttribs !== unknownType) {
|
||||
const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol);
|
||||
apparentAttributesType = intersectTypes(
|
||||
typeParams
|
||||
? createTypeReference(<GenericType>intrinsicClassAttribs, fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isJs))
|
||||
: intrinsicClassAttribs,
|
||||
apparentAttributesType
|
||||
);
|
||||
}
|
||||
|
||||
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context);
|
||||
if (intrinsicAttribs !== unknownType) {
|
||||
apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
|
||||
}
|
||||
|
||||
return apparentAttributesType;
|
||||
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context);
|
||||
if (intrinsicAttribs !== unknownType) {
|
||||
apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType);
|
||||
}
|
||||
|
||||
return apparentAttributesType;
|
||||
}
|
||||
}
|
||||
|
||||
function getJsxPropsTypeFromConstructSignature(sig: Signature, isJs: boolean, context: JsxOpeningLikeElement) {
|
||||
const hostClassType = getReturnTypeOfSignature(sig);
|
||||
if (hostClassType) {
|
||||
return getJsxPropsTypeFromClassType(hostClassType, isJs, context, /*reportErrors*/ false);
|
||||
}
|
||||
return getJsxPropsTypeFromCallSignature(sig, context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If the given type is an object or union type with a single signature, and if that signature has at
|
||||
// least as many parameters as the given function, return the signature. Otherwise return undefined.
|
||||
function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
|
||||
@@ -15556,31 +15545,7 @@ namespace ts {
|
||||
return links.resolvedSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JSX element that is a class element, finds the Element Instance Type. If the
|
||||
* element is not a class element, or the class element type cannot be determined, returns 'undefined'.
|
||||
* For example, in the element <MyClass>, the element instance type is `MyClass` (not `typeof MyClass`).
|
||||
*/
|
||||
function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type) {
|
||||
Debug.assert(!(valueType.flags & TypeFlags.Union));
|
||||
if (isTypeAny(valueType)) {
|
||||
// Short-circuit if the class tag is using an element type 'any'
|
||||
return anyType;
|
||||
}
|
||||
|
||||
// Resolve the signatures, preferring constructor
|
||||
let signatures = getSignaturesOfType(valueType, SignatureKind.Construct);
|
||||
if (signatures.length === 0) {
|
||||
// No construct signatures, try call signatures
|
||||
signatures = getSignaturesOfType(valueType, SignatureKind.Call);
|
||||
if (signatures.length === 0) {
|
||||
// We found no signatures at all, which is an error
|
||||
error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName));
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate in context of source type
|
||||
function instantiateJsxSignatures(node: JsxOpeningLikeElement, signatures: Signature[]) {
|
||||
const instantiatedSignatures = [];
|
||||
let candidateForTypeArgumentError: Signature;
|
||||
let hasTypeArgumentError: boolean = !!node.typeArguments;
|
||||
@@ -15605,7 +15570,6 @@ namespace ts {
|
||||
instantiatedSignatures.push(signature);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.typeArguments && hasTypeArgumentError) {
|
||||
if (candidateForTypeArgumentError) {
|
||||
checkTypeArguments(candidateForTypeArgumentError, node.typeArguments, /*reportErrors*/ true);
|
||||
@@ -15615,8 +15579,7 @@ namespace ts {
|
||||
diagnostics.add(getTypeArgumentArityError(node, signatures, node.typeArguments));
|
||||
}
|
||||
}
|
||||
|
||||
return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
return instantiatedSignatures;
|
||||
}
|
||||
|
||||
function getJsxSignatureTypeArgumentInstantiation(signature: Signature, node: JsxOpeningLikeElement, isJavascript: boolean, reportErrors?: boolean) {
|
||||
@@ -15827,8 +15790,12 @@ namespace ts {
|
||||
}), UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
// Shortcircuit any
|
||||
if (isTypeAny(elementType)) {
|
||||
return elementType;
|
||||
}
|
||||
// If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type
|
||||
if (elementType.flags & TypeFlags.String) {
|
||||
else if (elementType.flags & TypeFlags.String) {
|
||||
return anyType;
|
||||
}
|
||||
else if (elementType.flags & TypeFlags.StringLiteral) {
|
||||
@@ -15854,7 +15821,22 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get the element instance type (the result of newing or invoking this tag)
|
||||
const elemInstanceType = getJsxElementInstanceType(openingLikeElement, elementType);
|
||||
|
||||
// Resolve the signatures, preferring constructor
|
||||
let signatures = getSignaturesOfType(elementType, SignatureKind.Construct);
|
||||
if (signatures.length === 0) {
|
||||
// No construct signatures, try call signatures
|
||||
signatures = getSignaturesOfType(elementType, SignatureKind.Call);
|
||||
if (signatures.length === 0) {
|
||||
// We found no signatures at all, which is an error
|
||||
error(openingLikeElement.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(openingLikeElement.tagName));
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate in context of source type
|
||||
const instantiatedSignatures = instantiateJsxSignatures(openingLikeElement, signatures);
|
||||
const elemInstanceType = getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
|
||||
// If we should include all stateless attributes type, then get all attributes type from all stateless function signature.
|
||||
// Otherwise get only attributes type from the signature picked by choose-overload logic.
|
||||
@@ -15871,7 +15853,8 @@ namespace ts {
|
||||
checkTypeRelatedTo(elemInstanceType, elementClassType, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements);
|
||||
}
|
||||
|
||||
return getJsxPropsTypeFromClassType(elemInstanceType, isInJavaScriptFile(openingLikeElement), openingLikeElement, /*reportErrors*/ true);
|
||||
const isJs = isInJavaScriptFile(openingLikeElement);
|
||||
return getUnionType(map(instantiatedSignatures, sig => getJsxPropsTypeFromClassType(sig, isJs, openingLikeElement, /*reportErrors*/ true)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18469,8 +18452,13 @@ namespace ts {
|
||||
pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos]) : anyType;
|
||||
}
|
||||
|
||||
|
||||
function getTypeOfFirstParameterOfSignature(signature: Signature) {
|
||||
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : neverType;
|
||||
return getTypeOfFirstParameterOfSignatureWithFallback(signature, neverType);
|
||||
}
|
||||
|
||||
function getTypeOfFirstParameterOfSignatureWithFallback(signature: Signature, fallbackType: Type) {
|
||||
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType;
|
||||
}
|
||||
|
||||
function inferFromAnnotatedParameters(signature: Signature, context: Signature, mapper: TypeMapper) {
|
||||
@@ -27565,7 +27553,7 @@ namespace ts {
|
||||
export const JSX = "JSX" as __String;
|
||||
export const IntrinsicElements = "IntrinsicElements" as __String;
|
||||
export const ElementClass = "ElementClass" as __String;
|
||||
export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String;
|
||||
export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; // TODO: Deprecate and remove support
|
||||
export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String;
|
||||
export const Element = "Element" as __String;
|
||||
export const IntrinsicAttributes = "IntrinsicAttributes" as __String;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
tests/cases/conformance/jsx/file.tsx(13,1): error TS2605: JSX element type '{ x: number; }' is not a constructor function for JSX elements.
|
||||
Property 'render' is missing in type '{ x: number; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(13,7): error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(19,7): error TS2322: Type '{ x: number; render: number; }' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
|
||||
declare module JSX {
|
||||
interface Element { }
|
||||
interface ElementClass {
|
||||
@@ -19,10 +21,14 @@ tests/cases/conformance/jsx/file.tsx(13,1): error TS2605: JSX element type '{ x:
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2605: JSX element type '{ x: number; }' is not a constructor function for JSX elements.
|
||||
!!! error TS2605: Property 'render' is missing in type '{ x: number; }'.
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
|
||||
|
||||
interface Obj2type {
|
||||
(n: string): { x: number; render: any; };
|
||||
}
|
||||
var Obj2: Obj2type;
|
||||
<Obj2 x={32} render={100} />; // OK
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ x: number; render: number; }' is not assignable to type 'string'.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
tests/cases/conformance/jsx/file.tsx(3,12): error TS2608: The global type 'JSX.ElementAttributesProperty' may not have more than one property.
|
||||
tests/cases/conformance/jsx/file.tsx(11,7): error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
|
||||
declare module JSX {
|
||||
interface Element { }
|
||||
interface ElementAttributesProperty { pr1: any; pr2: any; }
|
||||
@@ -15,4 +16,6 @@ tests/cases/conformance/jsx/file.tsx(3,12): error TS2608: The global type 'JSX.E
|
||||
}
|
||||
var Obj1: Obj1type;
|
||||
<Obj1 x={10} />; // Error
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'string'.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
tests/cases/conformance/jsx/file.tsx(11,1): error TS2322: Type '{}' is not assignable to type 'string | number'.
|
||||
Type '{}' is not assignable to type 'number'.
|
||||
tests/cases/conformance/jsx/file.tsx(18,1): error TS2322: Type '{}' is not assignable to type 'string | number'.
|
||||
Type '{}' is not assignable to type 'number'.
|
||||
tests/cases/conformance/jsx/file.tsx(25,7): error TS2322: Type '{ x: number; }' is not assignable to type 'string | number'.
|
||||
Type '{ x: number; }' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
|
||||
declare module JSX {
|
||||
interface Element { something; }
|
||||
interface IntrinsicElements { }
|
||||
}
|
||||
|
||||
interface Obj1 {
|
||||
new(n: string): { x: number };
|
||||
new(n: number): { y: string };
|
||||
}
|
||||
var Obj1: Obj1;
|
||||
<Obj1 />; // Error, return type is not an object type
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'string | number'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'number'.
|
||||
|
||||
interface Obj2 {
|
||||
(n: string): { x: number };
|
||||
(n: number): { y: string };
|
||||
}
|
||||
var Obj2: Obj2;
|
||||
<Obj2 />; // Error, return type is not an object type
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'string | number'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'number'.
|
||||
|
||||
interface Obj3 {
|
||||
(n: string): { x: number };
|
||||
(n: number): { x: number; y: string };
|
||||
}
|
||||
var Obj3: Obj3;
|
||||
<Obj3 x={42} />; // OK
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'string | number'.
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'number'.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
tests/cases/compiler/file.tsx(11,14): error TS2322: Type '{ prop: number; }' is not assignable to type 'Record<string, string>'.
|
||||
Property 'prop' is incompatible with index signature.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/file.tsx (1 errors) ====
|
||||
declare namespace JSX {
|
||||
interface Element {
|
||||
render(): Element | string | false;
|
||||
}
|
||||
}
|
||||
|
||||
function SFC<T>(props: Record<string, T>) {
|
||||
return '';
|
||||
}
|
||||
|
||||
<SFC<string> prop={1}></SFC>; // should error
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{ prop: number; }' is not assignable to type 'Record<string, string>'.
|
||||
!!! error TS2322: Property 'prop' is incompatible with index signature.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//// [file.tsx]
|
||||
declare namespace JSX {
|
||||
interface Element {
|
||||
render(): Element | string | false;
|
||||
}
|
||||
}
|
||||
|
||||
function SFC<T>(props: Record<string, T>) {
|
||||
return '';
|
||||
}
|
||||
|
||||
<SFC<string> prop={1}></SFC>; // should error
|
||||
|
||||
|
||||
//// [file.jsx]
|
||||
function SFC(props) {
|
||||
return '';
|
||||
}
|
||||
<SFC prop={1}></SFC>; // should error
|
||||
@@ -0,0 +1,28 @@
|
||||
=== tests/cases/compiler/file.tsx ===
|
||||
declare namespace JSX {
|
||||
>JSX : Symbol(JSX, Decl(file.tsx, 0, 0))
|
||||
|
||||
interface Element {
|
||||
>Element : Symbol(Element, Decl(file.tsx, 0, 23))
|
||||
|
||||
render(): Element | string | false;
|
||||
>render : Symbol(Element.render, Decl(file.tsx, 1, 23))
|
||||
>Element : Symbol(Element, Decl(file.tsx, 0, 23))
|
||||
}
|
||||
}
|
||||
|
||||
function SFC<T>(props: Record<string, T>) {
|
||||
>SFC : Symbol(SFC, Decl(file.tsx, 4, 1))
|
||||
>T : Symbol(T, Decl(file.tsx, 6, 13))
|
||||
>props : Symbol(props, Decl(file.tsx, 6, 16))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(file.tsx, 6, 13))
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
<SFC<string> prop={1}></SFC>; // should error
|
||||
>SFC : Symbol(SFC, Decl(file.tsx, 4, 1))
|
||||
>prop : Symbol(prop, Decl(file.tsx, 10, 12))
|
||||
>SFC : Symbol(SFC, Decl(file.tsx, 4, 1))
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
=== tests/cases/compiler/file.tsx ===
|
||||
declare namespace JSX {
|
||||
>JSX : any
|
||||
|
||||
interface Element {
|
||||
>Element : Element
|
||||
|
||||
render(): Element | string | false;
|
||||
>render : () => string | false | Element
|
||||
>Element : Element
|
||||
>false : false
|
||||
}
|
||||
}
|
||||
|
||||
function SFC<T>(props: Record<string, T>) {
|
||||
>SFC : <T>(props: Record<string, T>) => string
|
||||
>T : T
|
||||
>props : Record<string, T>
|
||||
>Record : Record<K, T>
|
||||
>T : T
|
||||
|
||||
return '';
|
||||
>'' : ""
|
||||
}
|
||||
|
||||
<SFC<string> prop={1}></SFC>; // should error
|
||||
><SFC<string> prop={1}></SFC> : JSX.Element
|
||||
>SFC : <T>(props: Record<string, T>) => string
|
||||
>prop : number
|
||||
>1 : 1
|
||||
>SFC : <T>(props: Record<string, T>) => string
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
tests/cases/conformance/jsx/tsxTypeErrors.tsx(25,19): error TS2339: Property 'reqd' does not exist on type '{}'.
|
||||
tests/cases/conformance/jsx/tsxTypeErrors.tsx(31,19): error TS2339: Property 'pt' does not exist on type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/tsxTypeErrors.tsx (2 errors) ====
|
||||
// A built-in element (OK)
|
||||
var a1 = <div id="foo" />;
|
||||
|
||||
// A built-in element with a mistyped property (error)
|
||||
var a2 = <img srce="foo.jpg" />
|
||||
|
||||
// A built-in element with a badly-typed attribute value (error)
|
||||
var thing = { oops: 100 };
|
||||
var a3 = <div id={thing} />
|
||||
|
||||
// Mistyped html name (error)
|
||||
var e1 = <imag src="bar.jpg" />
|
||||
|
||||
// A custom type
|
||||
class MyClass {
|
||||
props: {
|
||||
pt?: { x: number; y: number; };
|
||||
name?: string;
|
||||
reqd: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's use it
|
||||
// TODO: Error on missing 'reqd'
|
||||
var b1 = <MyClass reqd={true} />;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'reqd' does not exist on type '{}'.
|
||||
|
||||
// Mistyped attribute member
|
||||
// sample.tsx(23,22): error TS2322: Type '{ x: number; y: string; }' is not assignable to type '{ x: number; y: number; }'.
|
||||
// Types of property 'y' are incompatible.
|
||||
// Type 'string' is not assignable to type 'number'.
|
||||
var b2 = <MyClass pt={{x: 4, y: 'oops'}} />;
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'pt' does not exist on type '{}'.
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// @jsx: preserve
|
||||
// @filename: file.tsx
|
||||
declare namespace JSX {
|
||||
interface Element {
|
||||
render(): Element | string | false;
|
||||
}
|
||||
}
|
||||
|
||||
function SFC<T>(props: Record<string, T>) {
|
||||
return '';
|
||||
}
|
||||
|
||||
<SFC<string> prop={1}></SFC>; // should error
|
||||
Reference in New Issue
Block a user