Skip to content

Commit 074f208

Browse files
authored
Fix JSX inference with excess properties (#53810)
1 parent b0c8020 commit 074f208

File tree

4 files changed

+150
-1
lines changed

4 files changed

+150
-1
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32629,8 +32629,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3262932629
// can be specified by users through attributes property.
3263032630
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
3263132631
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode);
32632+
const checkAttributesType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(attributesType) : attributesType;
3263232633
return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate(
32633-
attributesType,
32634+
checkAttributesType,
3263432635
paramType,
3263532636
relation,
3263632637
reportErrors ? node.tagName : undefined,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
=== tests/cases/compiler/typeInferenceWithExcessPropertiesJsx.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import React = require('react');
5+
>React : Symbol(React, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 0, 0))
6+
7+
type TranslationEntry = {
8+
>TranslationEntry : Symbol(TranslationEntry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 2, 32))
9+
10+
args: [] | [unknown];
11+
>args : Symbol(args, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 4, 25))
12+
}
13+
type Translations = {
14+
>Translations : Symbol(Translations, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 6, 1))
15+
16+
a: { args: [string] },
17+
>a : Symbol(a, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 7, 21))
18+
>args : Symbol(args, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 8, 8))
19+
20+
b: { args: [] }
21+
>b : Symbol(b, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 8, 26))
22+
>args : Symbol(args, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 9, 8))
23+
}
24+
type TProps<Entry extends TranslationEntry> = {
25+
>TProps : Symbol(TProps, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 10, 1))
26+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 11, 12))
27+
>TranslationEntry : Symbol(TranslationEntry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 2, 32))
28+
29+
getTranslationEntry: (allTranslations: Translations) => Entry,
30+
>getTranslationEntry : Symbol(getTranslationEntry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 11, 47))
31+
>allTranslations : Symbol(allTranslations, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 12, 26))
32+
>Translations : Symbol(Translations, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 6, 1))
33+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 11, 12))
34+
35+
} & (Entry["args"] extends [unknown] ? {
36+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 11, 12))
37+
38+
args: Entry["args"][0]
39+
>args : Symbol(args, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 13, 40))
40+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 11, 12))
41+
42+
} : {});
43+
44+
declare function T<Entry extends TranslationEntry>(
45+
>T : Symbol(T, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 15, 8))
46+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 17, 19))
47+
>TranslationEntry : Symbol(TranslationEntry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 2, 32))
48+
49+
props: TProps<Entry>
50+
>props : Symbol(props, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 17, 51))
51+
>TProps : Symbol(TProps, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 10, 1))
52+
>Entry : Symbol(Entry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 17, 19))
53+
54+
): JSX.Element;
55+
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
56+
>Element : Symbol(JSX.Element, Decl(react16.d.ts, 2494, 23))
57+
58+
<T getTranslationEntry={(allTranslations) => allTranslations.a} args="a" />
59+
>T : Symbol(T, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 15, 8))
60+
>getTranslationEntry : Symbol(getTranslationEntry, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 21, 2))
61+
>allTranslations : Symbol(allTranslations, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 21, 25))
62+
>allTranslations.a : Symbol(a, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 7, 21))
63+
>allTranslations : Symbol(allTranslations, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 21, 25))
64+
>a : Symbol(a, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 7, 21))
65+
>args : Symbol(args, Decl(typeInferenceWithExcessPropertiesJsx.tsx, 21, 63))
66+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
=== tests/cases/compiler/typeInferenceWithExcessPropertiesJsx.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
4+
import React = require('react');
5+
>React : typeof React
6+
7+
type TranslationEntry = {
8+
>TranslationEntry : { args: [] | [unknown]; }
9+
10+
args: [] | [unknown];
11+
>args : [] | [unknown]
12+
}
13+
type Translations = {
14+
>Translations : { a: { args: [string];}; b: { args: [];}; }
15+
16+
a: { args: [string] },
17+
>a : { args: [string]; }
18+
>args : [string]
19+
20+
b: { args: [] }
21+
>b : { args: []; }
22+
>args : []
23+
}
24+
type TProps<Entry extends TranslationEntry> = {
25+
>TProps : TProps<Entry>
26+
27+
getTranslationEntry: (allTranslations: Translations) => Entry,
28+
>getTranslationEntry : (allTranslations: Translations) => Entry
29+
>allTranslations : Translations
30+
31+
} & (Entry["args"] extends [unknown] ? {
32+
args: Entry["args"][0]
33+
>args : Entry["args"][0]
34+
35+
} : {});
36+
37+
declare function T<Entry extends TranslationEntry>(
38+
>T : <Entry extends TranslationEntry>(props: TProps<Entry>) => JSX.Element
39+
40+
props: TProps<Entry>
41+
>props : TProps<Entry>
42+
43+
): JSX.Element;
44+
>JSX : any
45+
46+
<T getTranslationEntry={(allTranslations) => allTranslations.a} args="a" />
47+
><T getTranslationEntry={(allTranslations) => allTranslations.a} args="a" /> : JSX.Element
48+
>T : <Entry extends TranslationEntry>(props: TProps<Entry>) => JSX.Element
49+
>getTranslationEntry : (allTranslations: Translations) => { args: [string]; }
50+
>(allTranslations) => allTranslations.a : (allTranslations: Translations) => { args: [string]; }
51+
>allTranslations : Translations
52+
>allTranslations.a : { args: [string]; }
53+
>allTranslations : Translations
54+
>a : { args: [string]; }
55+
>args : string
56+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @strict: true
2+
// @noEmit: true
3+
// @jsx: preserve
4+
5+
/// <reference path="/.lib/react16.d.ts" />
6+
7+
import React = require('react');
8+
9+
type TranslationEntry = {
10+
args: [] | [unknown];
11+
}
12+
type Translations = {
13+
a: { args: [string] },
14+
b: { args: [] }
15+
}
16+
type TProps<Entry extends TranslationEntry> = {
17+
getTranslationEntry: (allTranslations: Translations) => Entry,
18+
} & (Entry["args"] extends [unknown] ? {
19+
args: Entry["args"][0]
20+
} : {});
21+
22+
declare function T<Entry extends TranslationEntry>(
23+
props: TProps<Entry>
24+
): JSX.Element;
25+
26+
<T getTranslationEntry={(allTranslations) => allTranslations.a} args="a" />

0 commit comments

Comments
 (0)