Skip to content

Commit 2f4bd00

Browse files
committed
add support for jsx attributes
1 parent c286684 commit 2f4bd00

File tree

5 files changed

+326
-2
lines changed

5 files changed

+326
-2
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13613,7 +13613,7 @@ namespace ts {
1361313613
function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
1361413614
let assignmentVariance;
1361513615

13616-
if (strictAssignment) {
13616+
if (strictAssignment && sourceProp.valueDeclaration) {
1361713617
const {aliasSymbol, symbol} = getTypeOfSymbol(targetProp);
1361813618
const propEscapedName = (aliasSymbol && symbolName(aliasSymbol)) || (symbol && symbolName(symbol));
1361913619
const targetPropIsReadonly = contains(["Readonly", "ReadonlyArray", "ReadonlyMap", "ReadonlySet"], propEscapedName);
@@ -13636,6 +13636,15 @@ namespace ts {
1363613636
// PropertyDeclarations are properties declared within classes
1363713637
assignmentVariance = !targetPropIsReadonly && targetPropIsArray ? VarianceFlags.Invariant : undefined;
1363813638
}
13639+
else if (isJsxAttribute(sourceProp.valueDeclaration)) {
13640+
const {initializer} = sourceProp.valueDeclaration;
13641+
if (initializer && isJsxExpression(initializer)) {
13642+
const {expression} = initializer;
13643+
if (expression && isIdentifier(expression)) {
13644+
assignmentVariance = VarianceFlags.Invariant;
13645+
}
13646+
}
13647+
}
1363913648
}
1364013649

1364113650
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
@@ -21135,7 +21144,6 @@ namespace ts {
2113521144
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
2113621145
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode);
2113721146

21138-
// TODO: set assignmentVariance to Invariant for props that identifiers
2113921147
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes);
2114021148
}
2114121149

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//// [strictAssignment5.tsx]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
import React from "react";
4+
5+
module StrictAssignment5 {
6+
class Animal {}
7+
class Cat { purr() {} }
8+
class Dog { bark() {} }
9+
10+
type Props = {
11+
animals: Animal[],
12+
};
13+
14+
class Foo extends React.Component<Props> {
15+
render() {
16+
return "foo";
17+
}
18+
}
19+
20+
const cats: Cat[] = [new Cat];
21+
<Foo animals={cats} />; // error
22+
<Foo animals={[new Cat]} />; // okay
23+
24+
type ReadonlyProps = {
25+
animals: ReadonlyArray<Animal>,
26+
};
27+
28+
class Bar extends React.Component<ReadonlyProps> {
29+
render() {
30+
return "foo";
31+
}
32+
}
33+
34+
<Bar animals={cats} />; // okay
35+
}
36+
37+
38+
//// [strictAssignment5.js]
39+
"use strict";
40+
var __extends = (this && this.__extends) || (function () {
41+
var extendStatics = function (d, b) {
42+
extendStatics = Object.setPrototypeOf ||
43+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
44+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
45+
return extendStatics(d, b);
46+
};
47+
return function (d, b) {
48+
extendStatics(d, b);
49+
function __() { this.constructor = d; }
50+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
51+
};
52+
})();
53+
var __importDefault = (this && this.__importDefault) || function (mod) {
54+
return (mod && mod.__esModule) ? mod : { "default": mod };
55+
};
56+
exports.__esModule = true;
57+
/// <reference path="react16.d.ts" />
58+
var react_1 = __importDefault(require("react"));
59+
var StrictAssignment5;
60+
(function (StrictAssignment5) {
61+
var Animal = /** @class */ (function () {
62+
function Animal() {
63+
}
64+
return Animal;
65+
}());
66+
var Cat = /** @class */ (function () {
67+
function Cat() {
68+
}
69+
Cat.prototype.purr = function () { };
70+
return Cat;
71+
}());
72+
var Dog = /** @class */ (function () {
73+
function Dog() {
74+
}
75+
Dog.prototype.bark = function () { };
76+
return Dog;
77+
}());
78+
var Foo = /** @class */ (function (_super) {
79+
__extends(Foo, _super);
80+
function Foo() {
81+
return _super !== null && _super.apply(this, arguments) || this;
82+
}
83+
Foo.prototype.render = function () {
84+
return "foo";
85+
};
86+
return Foo;
87+
}(react_1["default"].Component));
88+
var cats = [new Cat];
89+
react_1["default"].createElement(Foo, { animals: cats }); // error
90+
react_1["default"].createElement(Foo, { animals: [new Cat] }); // okay
91+
var Bar = /** @class */ (function (_super) {
92+
__extends(Bar, _super);
93+
function Bar() {
94+
return _super !== null && _super.apply(this, arguments) || this;
95+
}
96+
Bar.prototype.render = function () {
97+
return "foo";
98+
};
99+
return Bar;
100+
}(react_1["default"].Component));
101+
react_1["default"].createElement(Bar, { animals: cats }); // okay
102+
})(StrictAssignment5 || (StrictAssignment5 = {}));
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
=== tests/cases/compiler/strictAssignment5.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
import React from "react";
4+
>React : Symbol(React, Decl(strictAssignment5.tsx, 1, 6))
5+
6+
module StrictAssignment5 {
7+
>StrictAssignment5 : Symbol(StrictAssignment5, Decl(strictAssignment5.tsx, 1, 26))
8+
9+
class Animal {}
10+
>Animal : Symbol(Animal, Decl(strictAssignment5.tsx, 3, 26))
11+
12+
class Cat { purr() {} }
13+
>Cat : Symbol(Cat, Decl(strictAssignment5.tsx, 4, 19))
14+
>purr : Symbol(Cat.purr, Decl(strictAssignment5.tsx, 5, 15))
15+
16+
class Dog { bark() {} }
17+
>Dog : Symbol(Dog, Decl(strictAssignment5.tsx, 5, 27))
18+
>bark : Symbol(Dog.bark, Decl(strictAssignment5.tsx, 6, 15))
19+
20+
type Props = {
21+
>Props : Symbol(Props, Decl(strictAssignment5.tsx, 6, 27))
22+
23+
animals: Animal[],
24+
>animals : Symbol(animals, Decl(strictAssignment5.tsx, 8, 18))
25+
>Animal : Symbol(Animal, Decl(strictAssignment5.tsx, 3, 26))
26+
27+
};
28+
29+
class Foo extends React.Component<Props> {
30+
>Foo : Symbol(Foo, Decl(strictAssignment5.tsx, 10, 6))
31+
>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
32+
>React : Symbol(React, Decl(strictAssignment5.tsx, 1, 6))
33+
>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
34+
>Props : Symbol(Props, Decl(strictAssignment5.tsx, 6, 27))
35+
36+
render() {
37+
>render : Symbol(Foo.render, Decl(strictAssignment5.tsx, 12, 46))
38+
39+
return "foo";
40+
}
41+
}
42+
43+
const cats: Cat[] = [new Cat];
44+
>cats : Symbol(cats, Decl(strictAssignment5.tsx, 18, 9))
45+
>Cat : Symbol(Cat, Decl(strictAssignment5.tsx, 4, 19))
46+
>Cat : Symbol(Cat, Decl(strictAssignment5.tsx, 4, 19))
47+
48+
<Foo animals={cats} />; // error
49+
>Foo : Symbol(Foo, Decl(strictAssignment5.tsx, 10, 6))
50+
>animals : Symbol(animals, Decl(strictAssignment5.tsx, 19, 8))
51+
>cats : Symbol(cats, Decl(strictAssignment5.tsx, 18, 9))
52+
53+
<Foo animals={[new Cat]} />; // okay
54+
>Foo : Symbol(Foo, Decl(strictAssignment5.tsx, 10, 6))
55+
>animals : Symbol(animals, Decl(strictAssignment5.tsx, 20, 8))
56+
>Cat : Symbol(Cat, Decl(strictAssignment5.tsx, 4, 19))
57+
58+
type ReadonlyProps = {
59+
>ReadonlyProps : Symbol(ReadonlyProps, Decl(strictAssignment5.tsx, 20, 32))
60+
61+
animals: ReadonlyArray<Animal>,
62+
>animals : Symbol(animals, Decl(strictAssignment5.tsx, 22, 26))
63+
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
64+
>Animal : Symbol(Animal, Decl(strictAssignment5.tsx, 3, 26))
65+
66+
};
67+
68+
class Bar extends React.Component<ReadonlyProps> {
69+
>Bar : Symbol(Bar, Decl(strictAssignment5.tsx, 24, 6))
70+
>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
71+
>React : Symbol(React, Decl(strictAssignment5.tsx, 1, 6))
72+
>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94))
73+
>ReadonlyProps : Symbol(ReadonlyProps, Decl(strictAssignment5.tsx, 20, 32))
74+
75+
render() {
76+
>render : Symbol(Bar.render, Decl(strictAssignment5.tsx, 26, 54))
77+
78+
return "foo";
79+
}
80+
}
81+
82+
<Bar animals={cats} />; // okay
83+
>Bar : Symbol(Bar, Decl(strictAssignment5.tsx, 24, 6))
84+
>animals : Symbol(animals, Decl(strictAssignment5.tsx, 32, 8))
85+
>cats : Symbol(cats, Decl(strictAssignment5.tsx, 18, 9))
86+
}
87+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
=== tests/cases/compiler/strictAssignment5.tsx ===
2+
/// <reference path="react16.d.ts" />
3+
import React from "react";
4+
>React : typeof React
5+
6+
module StrictAssignment5 {
7+
>StrictAssignment5 : typeof StrictAssignment5
8+
9+
class Animal {}
10+
>Animal : Animal
11+
12+
class Cat { purr() {} }
13+
>Cat : Cat
14+
>purr : () => void
15+
16+
class Dog { bark() {} }
17+
>Dog : Dog
18+
>bark : () => void
19+
20+
type Props = {
21+
>Props : { animals: Animal[]; }
22+
23+
animals: Animal[],
24+
>animals : Animal[]
25+
26+
};
27+
28+
class Foo extends React.Component<Props> {
29+
>Foo : Foo
30+
>React.Component : React.Component<{ animals: Animal[]; }, {}, any>
31+
>React : typeof React
32+
>Component : typeof React.Component
33+
34+
render() {
35+
>render : () => string
36+
37+
return "foo";
38+
>"foo" : "foo"
39+
}
40+
}
41+
42+
const cats: Cat[] = [new Cat];
43+
>cats : Cat[]
44+
>[new Cat] : Cat[]
45+
>new Cat : Cat
46+
>Cat : typeof Cat
47+
48+
<Foo animals={cats} />; // error
49+
><Foo animals={cats} /> : JSX.Element
50+
>Foo : typeof Foo
51+
>animals : Cat[]
52+
>cats : Cat[]
53+
54+
<Foo animals={[new Cat]} />; // okay
55+
><Foo animals={[new Cat]} /> : JSX.Element
56+
>Foo : typeof Foo
57+
>animals : Cat[]
58+
>[new Cat] : Cat[]
59+
>new Cat : Cat
60+
>Cat : typeof Cat
61+
62+
type ReadonlyProps = {
63+
>ReadonlyProps : { animals: readonly Animal[]; }
64+
65+
animals: ReadonlyArray<Animal>,
66+
>animals : readonly Animal[]
67+
68+
};
69+
70+
class Bar extends React.Component<ReadonlyProps> {
71+
>Bar : Bar
72+
>React.Component : React.Component<{ animals: readonly Animal[]; }, {}, any>
73+
>React : typeof React
74+
>Component : typeof React.Component
75+
76+
render() {
77+
>render : () => string
78+
79+
return "foo";
80+
>"foo" : "foo"
81+
}
82+
}
83+
84+
<Bar animals={cats} />; // okay
85+
><Bar animals={cats} /> : JSX.Element
86+
>Bar : typeof Bar
87+
>animals : Cat[]
88+
>cats : Cat[]
89+
}
90+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// @jsx: react
2+
// @esModuleInterop: true
3+
// @strict: true
4+
/// <reference path="/.lib/react16.d.ts" />
5+
import React from "react";
6+
7+
module StrictAssignment5 {
8+
class Animal {}
9+
class Cat { purr() {} }
10+
class Dog { bark() {} }
11+
12+
type Props = {
13+
animals: Animal[],
14+
};
15+
16+
class Foo extends React.Component<Props> {
17+
render() {
18+
return "foo";
19+
}
20+
}
21+
22+
const cats: Cat[] = [new Cat];
23+
<Foo animals={cats} />; // error
24+
<Foo animals={[new Cat]} />; // okay
25+
26+
type ReadonlyProps = {
27+
animals: ReadonlyArray<Animal>,
28+
};
29+
30+
class Bar extends React.Component<ReadonlyProps> {
31+
render() {
32+
return "foo";
33+
}
34+
}
35+
36+
<Bar animals={cats} />; // okay
37+
}

0 commit comments

Comments
 (0)